diff --git a/build/meta/illumos-tools.p5m b/build/meta/illumos-tools.p5m index 67b6efe28b..b504886072 100644 --- a/build/meta/illumos-tools.p5m +++ b/build/meta/illumos-tools.p5m @@ -34,3 +34,4 @@ depend fmri=system/header type=require depend fmri=system/management/snmp/net-snmp type=require depend fmri=text/gnu-gettext type=require depend fmri=runtime/python-312 type=require +depend fmri=runtime/python-313 type=require diff --git a/build/meta/omnios-build-tools.p5m b/build/meta/omnios-build-tools.p5m index 4fbba838a6..66a32fc05e 100644 --- a/build/meta/omnios-build-tools.p5m +++ b/build/meta/omnios-build-tools.p5m @@ -55,6 +55,19 @@ depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/pyyaml-312 type=require depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/rapidjson-312 type=require depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/setuptools-rust-312 \ type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/coverage-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/crossenv-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/jsonrpclib-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/jsonschema-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/meson-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/packaging-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/pip-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/pycurl-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/pyopenssl-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/pyyaml-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/rapidjson-313 type=require +depend fmri=pkg://$(PKGPUBLISHER)/library/python-3/setuptools-rust-313 \ + type=require depend fmri=pkg://$(PKGPUBLISHER)/library/security/liboqs type=require depend fmri=pkg://$(PKGPUBLISHER)/library/security/openssl-11 type=require depend fmri=pkg://$(PKGPUBLISHER)/library/security/openssl-3 type=require @@ -65,6 +78,7 @@ depend fmri=pkg://$(PKGPUBLISHER)/runtime/java/openjdk21 type=require depend fmri=pkg://$(PKGPUBLISHER)/runtime/perl type=require depend fmri=pkg://$(PKGPUBLISHER)/runtime/python-27 type=require depend fmri=pkg://$(PKGPUBLISHER)/runtime/python-312 type=require +depend fmri=pkg://$(PKGPUBLISHER)/runtime/python-313 type=require depend fmri=pkg://$(PKGPUBLISHER)/service/network/tftp type=require depend fmri=pkg://$(PKGPUBLISHER)/system/header/header-audio type=require depend fmri=pkg://$(PKGPUBLISHER)/system/library type=require diff --git a/build/python312/local.mog b/build/python312/local.mog index f74f9489d9..dbb738cae8 100644 --- a/build/python312/local.mog +++ b/build/python312/local.mog @@ -44,9 +44,7 @@ license LICENSE license=PSFv2 set mediator-version $(PYTHONVER)> -# Let the default mediator priority take effect while the highest version is -# the default. -# set mediator-priority vendor> + set mediator-priority vendor> # Add mediated link for /usr/bin/python and python-config link path=usr/bin/python target=python3 diff --git a/build/python313/README b/build/python313/README new file mode 100644 index 0000000000..ab55408d02 --- /dev/null +++ b/build/python313/README @@ -0,0 +1,60 @@ + +Python module dependencies +-------------------------- + +setuptools + pip (and pip depends on setuptools! See "Bootstrap" below) + +pkg + cryptography + setuptools-rust + semantic-version + typing-extensions + tomli + six + cffi + pycparser + asn1crypto + idna + jsonrpclib + jsonschema + attrs + pyrsistent + js-regex + orjson + pycurl + rapidjson + coverage + pyopenssl + cryptography + +bhyve (brand) + pyyaml + +glib2 + meson + packaging + + +Bootstrap +--------- + +To bootstrap modules for a new python version, build 'setuptools' and 'pip' +with the '-f bootstrap' flag, and install these bootstrap packages: + + for m in setuptools pip; do + { cd $m; ./build.sh -f bootstrap -blt; } + done + pfexec pkg install {pip,setuptools}-3XX-bootstrap + +then build again, without the bootstrap flag: + + for m in setuptools pip; do + { cd $m; ./build.sh -blt; } + done + +and finally switch out the bootstrap packages for the real ones: + + pfexec pkg install --reject pip-3XX-bootstrap pip-3XX + pfexec pkg install --reject setuptools-3XX-bootstrap setuptools-3XX + diff --git a/build/python313/asn1crypto/build.sh b/build/python313/asn1crypto/build.sh new file mode 100755 index 0000000000..5b2835eda6 --- /dev/null +++ b/build/python313/asn1crypto/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/asn1crypto-313 +PROG=asn1crypto +inherit_ver python312/asn1crypto +SUMMARY="asn1crypto - Fast ASN.1 parser..." +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +BUILD_DEPENDS_IPS+="library/python-$PYMVER/setuptools-$SPYVER" + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/asn1crypto/local.mog b/build/python313/asn1crypto/local.mog new file mode 100644 index 0000000000..8db201d6fe --- /dev/null +++ b/build/python313/asn1crypto/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/attrs/build.sh b/build/python313/attrs/build.sh new file mode 100755 index 0000000000..ff8ad9c424 --- /dev/null +++ b/build/python313/attrs/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/attrs-313 +PROG=attrs +inherit_ver python312/attrs +SUMMARY="Python attrs" +DESC="Classes Without Boilerplate" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/attrs/local.mog b/build/python313/attrs/local.mog new file mode 100644 index 0000000000..06211aeb7c --- /dev/null +++ b/build/python313/attrs/local.mog @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + diff --git a/build/python313/build.sh b/build/python313/build.sh new file mode 100755 index 0000000000..9492b77c76 --- /dev/null +++ b/build/python313/build.sh @@ -0,0 +1,202 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../lib/build.sh + +PROG=Python +VER=3.13.1 +PKG=runtime/python-313 +MVER=${VER%.*} +SUMMARY="$PROG $MVER" +DESC="$SUMMARY" + +BUILD_DEPENDS_IPS=" + developer/build/autoconf + developer/pkg-config + ooce/developer/autoconf-archive +" +RUN_DEPENDS_IPS=" + compress/bzip2 + database/sqlite-3 + library/expat + library/libffi + library/libxml2 + library/ncurses + library/readline + library/security/openssl-3 + library/zlib + system/library/gcc-runtime + developer/object-file +" +XFORM_ARGS="-D PYTHONVER=$MVER" + +HARDLINK_TARGETS=" + usr/bin/python$MVER +" +SKIP_RTIME_CHECK=1 +NO_SONAME_EXPECTED=1 + +set_python_version $MVER +set_arch 64 + +# To expose the CMSG_ macros and new recvmsg() semantics for the socket module +set_standard XPG6 + +# Save arguments to the stack so that the mdb/pstack plugin can find them. +CFLAGS[amd64]+=" -msave-args" +CFLAGS[aarch64]+=" -mtls-dialect=trad" + +export CCSHARED="-fPIC" +CPPFLAGS+=" -I/usr/include/ncurses" +export DFLAGS=-64 +MAKE_ARGS=" + DFLAGS=-64 + DESTSHARED=/usr/lib/python$MVER/lib-dynload +" +MAKE_INSTALL_ARGS=DESTSHARED=/usr/lib/python$MVER/lib-dynload + +CONFIGURE_OPTS=" + --enable-shared + --with-system-expat + --enable-ipv6 + --without-ensurepip +" + +CONFIGURE_OPTS[amd64]+=" + --enable-optimizations + --with-dtrace +" + +CONFIGURE_OPTS[aarch64]+=" + --build=${TRIPLETS[amd64]%.*} + --with-build-python=$PYTHON + ac_cv_file__dev_ptmx=yes + ac_cv_file__dev_ptc=no +" + +# See https://bugs.python.org/issue25003 +# There is (was?) a bug in Python which massively slowed down os.urandom() +# due to the introduction of a call to getentropy() which blocks until there +# is sufficient entropy, and this affected pkg(7) significantly. +# We tell Python that we don't have getentropy(); Solaris does the same. +CONFIGURE_OPTS+=" ac_cv_func_getentropy=no " + +# hstrerror() is present in -lresolv, but if configure decides it's available +# then it uses it in a number of modules, which then don't link. +# Versions of Python < 3.11 did not detect this function but the new checks +# in 3.11 are less robust and think it's there even when it isn't. +# https://github.com/python/cpython/issues/89886#issuecomment-1106100113 +CONFIGURE_OPTS+=" ac_cv_func_hstrerror=no" + +# XXX +CONFIGURE_OPTS+=" ac_cv_readline_rl_startup_hook_takes_args=no" + +export DTRACE_CPP=$GCCPATH/bin/cpp + +CURSES_CFLAGS="-DHAVE_NCURSESW -D_XOPEN_SOURCE_EXTENDED" +LIBREADLINE_LIBS="-zrecord -lreadline -lncurses" +export CURSES_CFLAGS LIBREADLINE_LIBS + +build_init() { + typeset s=${SYSROOT[aarch64]} + + addpath PKG_CONFIG_PATH[aarch64] $s/usr/lib/pkgconfig + CONFIGURE_OPTS[aarch64]+=" --with-openssl=$s/usr" +} + +pre_configure() { + typeset arch="$1" + + save_variable CC + + PKG_CONFIG_PATH="${PKG_CONFIG_PATH[$arch]}" \ + PANEL_LIBS=`pkg-config --libs panel` + export PANEL_LIBS + + ! cross_arch $arch && return + + CC+=" --sysroot=${SYSROOT[$arch]}" +} + +post_configure() { + restore_variable CC +} + +post_install() { + python_compile \ + -o0 -o1 -o2 \ + -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' +} + +TESTSUITE_SED=" + 1,/Tests result:/ { + /Tests result:/p + d + } + / slowest tests:/,/^$/d + /Total duration/d + /^make:/d +" + +launch_testsuite() { + # Test selection + EXTRATESTOPTS="-uall,-audio,-gui,-largefile,-network -w" + EXTRATESTOPTS+=" --ignorefile $SRCDIR/files/test.exclude" + export EXTRATESTOPTS + if [ -z "$SKIP_TESTSUITE" ] && ( [ -n "$BATCH" ] || ask_to_testsuite ); then + # The compilall test (rightly) gets upset if we force timestamps + save_variable FORCE_PYC_TIMESTAMP + unset FORCE_PYC_TIMESTAMP + BATCH=1 run_testsuite "$@" $logf + for dir in $TMPDIR/$BUILDDIR; do + pushd $dir >/dev/null || logerr "chdir $dir" + $PFEXEC $MAKE test TESTOPTS=test_dtrace | tee -a $logf + # Reset ownership on the python cache directories/files which will + # have been created with root ownership. + $PFEXEC chown -R "`stat -c %U $SRCDIR`" . + popd >/dev/null + done + sed "$TESTSUITE_SED" < $logf > $SRCDIR/testsuite-d.log + [ -s $SRCDIR/testsuite-d.log ] \ + || echo "dtrace tests have failed" >> $SRCDIR/testsuite-d.log +} + +init +download_source $PROG $PROG $VER +patch_source +prep_build autoconf -autoreconf +build +launch_testsuite +test_dtrace +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/cffi/build.sh b/build/python313/cffi/build.sh new file mode 100755 index 0000000000..685a9ef847 --- /dev/null +++ b/build/python313/cffi/build.sh @@ -0,0 +1,44 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/cffi-313 +PROG=cffi +inherit_ver python312/cffi +SUMMARY="cffi" +DESC="Foreign Function Interface for Python calling C code" + +. $SRCDIR/../common.sh + +CFLAGS[aarch64]+=" -mtls-dialect=trad" + +RUN_DEPENDS_IPS+=" + library/python-$PYMVER/pycparser-$SPYVER +" + +REMOVE_PREVIOUS=1 + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/cffi/local.mog b/build/python313/cffi/local.mog new file mode 100644 index 0000000000..8db201d6fe --- /dev/null +++ b/build/python313/cffi/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/common.mog b/build/python313/common.mog new file mode 100644 index 0000000000..fd5f969bce --- /dev/null +++ b/build/python313/common.mog @@ -0,0 +1,33 @@ +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +# Newer setup tools creates entry point scripts which do things like: +# +# try: +# from importlib import metadata +# except ImportError: # for Python<3.8 +# import importlib_metadata as metadata +# +# This causes the IPS dependency resolver to assume that both importlib and +# importlib_metadata should exist, when in fact one is for Python < 3.8 and +# one is for later versions. Depending on the python version, one or the other +# will fail to be found. +# +# Therefore we bypass resolution of these dependencies. + + set pkg.depend.bypass-generate .*metadata.* > + +# XXX - due to cross compilation in the virtual environment, scripts end up +# with a venv shebang. This needs fixing but for now allow the failed +# dependency. +$(aarch64_ONLY) set pkg.depend.bypass-generate python> + diff --git a/build/python313/common.sh b/build/python313/common.sh new file mode 100644 index 0000000000..0ecfd60baf --- /dev/null +++ b/build/python313/common.sh @@ -0,0 +1,55 @@ +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +set_python_version 3.13 + +PYVER=$PYTHONVER # 3.13 +PYMVER=${PYTHONVER%%.*} # 3 +SPYVER=${PYTHONVER//./} # 313 + +RUN_DEPENDS_IPS="runtime/python-$SPYVER " +XFORM_ARGS=" + -D PYTHONVER=$PYVER + -D PYTHONLIB=${PYTHONLIB#/}/python$PYVER + -D PYVER=$PYVER + -D PYMVER=$PYMVER + -D SPYVER=$SPYVER +" + +PKGDIFF_HELPER=' + s:(vendor-packages/[^-]*)-[0-9.]*:\1-VERSION:g +' + +# Python modules ship shared objects with no SONAME +NO_SONAME_EXPECTED=1 + +# Use an extra directory level for building each module since there can be +# multiple versions of python being built in parallel and if they are built +# in the same directory then they will clobber each other. + +# Do this now, before changing the temporary base +init_repos + +TMPDIR+="/python$PYVER" +DTMPDIR+="/python$PYVER" +BASE_TMPDIR=$TMPDIR + +PEP518OPTS+=" --ignore-installed" + +# Use the same python version for dependency resolution +# XXX +#PKGDEPEND="/usr/bin/python$PYTHONVER -Es $PKGDEPEND" + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/coverage/README b/build/python313/coverage/README new file mode 100644 index 0000000000..8139e3dba0 --- /dev/null +++ b/build/python313/coverage/README @@ -0,0 +1,3 @@ + +Coverage is needed in order to run the pkg(7) test-suite + diff --git a/build/python313/coverage/build.sh b/build/python313/coverage/build.sh new file mode 100755 index 0000000000..d59bb2960a --- /dev/null +++ b/build/python313/coverage/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/coverage-313 +PROG=coverage +inherit_ver python312/coverage +SUMMARY="Python coverage module" +DESC="Code coverage testing for Python" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/coverage/local.mog b/build/python313/coverage/local.mog new file mode 100644 index 0000000000..51ca0dc8db --- /dev/null +++ b/build/python313/coverage/local.mog @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.txt license=Apache2 + + set pkg.depend.bypass-generate .* > + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + diff --git a/build/python313/crossenv/build.sh b/build/python313/crossenv/build.sh new file mode 100755 index 0000000000..63b71c6a1f --- /dev/null +++ b/build/python313/crossenv/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/crossenv-313 +PROG=crossenv +inherit_ver python312/crossenv +SUMMARY="A cross-compiling tool for Python extension modules" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/crossenv/local.mog b/build/python313/crossenv/local.mog new file mode 100644 index 0000000000..f882e2d24c --- /dev/null +++ b/build/python313/crossenv/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2023 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.txt license=MIT + diff --git a/build/python313/crossenv/patches/illumos.patch b/build/python313/crossenv/patches/illumos.patch new file mode 100644 index 0000000000..df449f46e8 --- /dev/null +++ b/build/python313/crossenv/patches/illumos.patch @@ -0,0 +1,12 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/crossenv/__init__.py a/crossenv/__init__.py +--- a~/crossenv/__init__.py 1970-01-01 00:00:00 ++++ a/crossenv/__init__.py 1970-01-01 00:00:00 +@@ -520,6 +520,8 @@ class CrossEnvBuilder(venv.EnvBuilder): + self.host_machine = self.host_gnu_type.split('-')[0] + + self.host_release = '' ++ if self.host_sysname == "sunos5": ++ self.host_release = '5.11' + if self.macosx_deployment_target: + try: + major, minor = self.macosx_deployment_target.split(".") diff --git a/build/python313/crossenv/patches/series b/build/python313/crossenv/patches/series new file mode 100644 index 0000000000..77f8d19dbb --- /dev/null +++ b/build/python313/crossenv/patches/series @@ -0,0 +1 @@ +illumos.patch diff --git a/build/python313/cryptography/build.sh b/build/python313/cryptography/build.sh new file mode 100755 index 0000000000..b59f199d02 --- /dev/null +++ b/build/python313/cryptography/build.sh @@ -0,0 +1,77 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/cryptography-313 +PROG=cryptography +inherit_ver python312/cryptography +SUMMARY="Cryptographic recipes and primitives" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +if [ "$BUILDARCH" = aarch64 ]; then + # This is the last version that does not require rust to build, so we use + # that for aarch64 for now. + VER=3.4.8 + export CRYPTOGRAPHY_DONT_BUILD_RUST=1 + set_patchdir patches.aarch64 +fi + +RUN_DEPENDS_IPS+=" + library/python-$PYMVER/six-$SPYVER + library/python-$PYMVER/cffi-$SPYVER + library/python-$PYMVER/asn1crypto-$SPYVER + library/python-$PYMVER/idna-$SPYVER +" + +# As of version 3.4, the cryptography module includes Rust code +BUILD_DEPENDS_IPS+=" + library/python-$PYMVER/setuptools-rust-$SPYVER +" + +PATH+=:$OOCEBIN + +# This package uses cffi as part of the build, and so the usual python cross +# compilation method (using the `crossenv` module) does not work. +# Somewhat surprisingly, this simple workaround does, although we have to +# use a compiler wrapper to strip options that are not applicable to +# the cross compiler and are otherwise picked by cffi from the native system +# info. +python_build_aarch64() { + typeset arch=aarch64 + + set_crossgcc $arch + + CFLAGS[$arch]+=" -mtls-dialect=trad" + + CC=$SRCDIR/files/gcc.aarch64 \ + PLATFORM=$arch \ + DESTDIR="$DESTDIR.$arch" \ + python_build_arch $arch +} + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/cryptography/files/gcc.aarch64 b/build/python313/cryptography/files/gcc.aarch64 new file mode 100755 index 0000000000..ef32ffee6f --- /dev/null +++ b/build/python313/cryptography/files/gcc.aarch64 @@ -0,0 +1,9 @@ +#!/bin/ksh + +set -- `echo $@ | sed ' + s/-m64//g + s/-msave-args//g + '` + +exec /opt/cross/aarch64/bin/gcc "$@" + diff --git a/build/python313/cryptography/local.mog b/build/python313/cryptography/local.mog new file mode 100644 index 0000000000..5c087f50c0 --- /dev/null +++ b/build/python313/cryptography/local.mog @@ -0,0 +1,15 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.BSD license=modified-BSD +license LICENSE.APACHE license=Apache2 + diff --git a/build/python313/cryptography/patches.aarch64/err.patch b/build/python313/cryptography/patches.aarch64/err.patch new file mode 100644 index 0000000000..aff6128983 --- /dev/null +++ b/build/python313/cryptography/patches.aarch64/err.patch @@ -0,0 +1,9 @@ +diff -wpruN '--exclude=*.orig' a~/src/_cffi_src/openssl/err.py a/src/_cffi_src/openssl/err.py +--- a~/src/_cffi_src/openssl/err.py 1970-01-01 00:00:00 ++++ a/src/_cffi_src/openssl/err.py 1970-01-01 00:00:00 +@@ -45,4 +45,5 @@ int ERR_GET_REASON(unsigned long); + """ + + CUSTOMIZATIONS = """ ++int (*ERR_GET_FUNC)(unsigned long) = NULL; + """ diff --git a/build/python313/cryptography/patches.aarch64/fips.patch b/build/python313/cryptography/patches.aarch64/fips.patch new file mode 100644 index 0000000000..b7a43af360 --- /dev/null +++ b/build/python313/cryptography/patches.aarch64/fips.patch @@ -0,0 +1,15 @@ +diff -wpruN '--exclude=*.orig' a~/src/_cffi_src/openssl/fips.py a/src/_cffi_src/openssl/fips.py +--- a~/src/_cffi_src/openssl/fips.py 1970-01-01 00:00:00 ++++ a/src/_cffi_src/openssl/fips.py 1970-01-01 00:00:00 +@@ -17,11 +17,7 @@ int FIPS_mode(void); + """ + + CUSTOMIZATIONS = """ +-#if CRYPTOGRAPHY_IS_LIBRESSL + static const long Cryptography_HAS_FIPS = 0; + int (*FIPS_mode_set)(int) = NULL; + int (*FIPS_mode)(void) = NULL; +-#else +-static const long Cryptography_HAS_FIPS = 1; +-#endif + """ diff --git a/build/python313/cryptography/patches.aarch64/series b/build/python313/cryptography/patches.aarch64/series new file mode 100644 index 0000000000..ba6e92e054 --- /dev/null +++ b/build/python313/cryptography/patches.aarch64/series @@ -0,0 +1,2 @@ +fips.patch +err.patch diff --git a/build/python313/cryptography/test b/build/python313/cryptography/test new file mode 100755 index 0000000000..acbee3ec79 --- /dev/null +++ b/build/python313/cryptography/test @@ -0,0 +1,9 @@ +#!/usr/bin/python3 + +from cryptography.fernet import Fernet +key = Fernet.generate_key() +f = Fernet(key) +token = f.encrypt(b"A really secret message. Not for prying eyes.") +print(token) +print(f.decrypt(token)) + diff --git a/build/python313/files/ctf.skip b/build/python313/files/ctf.skip new file mode 100644 index 0000000000..840994627e --- /dev/null +++ b/build/python313/files/ctf.skip @@ -0,0 +1 @@ +amd64/libpython3\.so$ diff --git a/build/python313/files/test.exclude b/build/python313/files/test.exclude new file mode 100644 index 0000000000..bb2caa79a1 --- /dev/null +++ b/build/python313/files/test.exclude @@ -0,0 +1,9 @@ +# +# Elements on the python test suite to skip on OmniOS +# +# illumos does not support multiple SCM_RIGHTS messages in a packet +*FDPassSeparate* +# +# Related to wchar_t differences on illumos +*.test_re.ReTests.test_locale_compiled +*.test_re.ReTests.test_locale_caching diff --git a/build/python313/idna/build.sh b/build/python313/idna/build.sh new file mode 100755 index 0000000000..ff3bfeae8a --- /dev/null +++ b/build/python313/idna/build.sh @@ -0,0 +1,37 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/idna-313 +PROG=idna +inherit_ver python312/idna +SUMMARY="Internationalized Domain Names in Applications (IDNA)" +DESC="Support for the Internationalised Domain Names in Applications (IDNA) " +DESC+="protocol as specified in RFC 5891" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/idna/local.mog b/build/python313/idna/local.mog new file mode 100644 index 0000000000..03564c6f5c --- /dev/null +++ b/build/python313/idna/local.mog @@ -0,0 +1,17 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.md license=modified-BSD + +# From version 2.7, the package sets the permissions of some files to 0700 + set mode 0644> + diff --git a/build/python313/js-regex/build.sh b/build/python313/js-regex/build.sh new file mode 100755 index 0000000000..d373f631bd --- /dev/null +++ b/build/python313/js-regex/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/js-regex-313 +PROG=js-regex +inherit_ver python312/js-regex +SUMMARY="A thin compatibility layer to use Javascript regular expressions" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/js-regex/files/MPLv2.0.txt b/build/python313/js-regex/files/MPLv2.0.txt new file mode 100644 index 0000000000..14e2f777f6 --- /dev/null +++ b/build/python313/js-regex/files/MPLv2.0.txt @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/build/python313/js-regex/local.mog b/build/python313/js-regex/local.mog new file mode 100644 index 0000000000..9a4e4c5da7 --- /dev/null +++ b/build/python313/js-regex/local.mog @@ -0,0 +1,15 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license files/MPLv2.0.txt license=MPLv2 + diff --git a/build/python313/jsonrpclib/build.sh b/build/python313/jsonrpclib/build.sh new file mode 100755 index 0000000000..42d55308a6 --- /dev/null +++ b/build/python313/jsonrpclib/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/jsonrpclib-313 +PROG=jsonrpclib +inherit_ver python312/jsonrpclib +SUMMARY="A Python JSON-RPC over HTTP that mirrors xmlrpclib syntax" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG v$VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/jsonrpclib/local.mog b/build/python313/jsonrpclib/local.mog new file mode 100644 index 0000000000..3c9e102194 --- /dev/null +++ b/build/python313/jsonrpclib/local.mog @@ -0,0 +1,15 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2018 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=Apache2 + set pkg.depend.bypass-generate .*> + diff --git a/build/python313/jsonschema/build.sh b/build/python313/jsonschema/build.sh new file mode 100755 index 0000000000..2a80508006 --- /dev/null +++ b/build/python313/jsonschema/build.sh @@ -0,0 +1,42 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/jsonschema-313 +PROG=jsonschema +inherit_ver python312/jsonschema +SUMMARY="An implementation of JSON Schema validation for Python" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +RUN_DEPENDS_IPS+=" + library/python-$PYMVER/attrs-$SPYVER + library/python-$PYMVER/pyrsistent-$SPYVER + library/python-$PYMVER/js-regex-$SPYVER +" + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package $SRCDIR/../common.mog +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/jsonschema/local.mog b/build/python313/jsonschema/local.mog new file mode 100644 index 0000000000..f25b0eb73e --- /dev/null +++ b/build/python313/jsonschema/local.mog @@ -0,0 +1,20 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license COPYING license=MIT + + drop> + + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + diff --git a/build/python313/local.mog b/build/python313/local.mog new file mode 100644 index 0000000000..b9b426f755 --- /dev/null +++ b/build/python313/local.mog @@ -0,0 +1,55 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=PSFv2 + +# Drop static library + drop> + +# Remove idle + drop > + drop> + +# Move binaries from usr/bin to private bin + \ + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + +# Remove test files + drop> + +# Prevent pkgdepend from reporting an error + set pkg.depend.bypass-generate .*> + +# Move libpython3.so and replace with a symlink that can be mediated. The +# mediator is applied below + emit \ + link path=%<1> target=libpython$(PYTHONVER)-stub.so > + edit path 3 $(PYTHONVER)-stub> + +# Set mediators on links in shared directories + set mediator python3> + set mediator python3> + set mediator python3> + + set mediator-version $(PYTHONVER)> + +# set mediator-priority vendor> + +# Add mediated link for /usr/bin/python and python-config +link path=usr/bin/python target=python3 +link path=usr/bin/python-config target=python3-config + set mediator python> + set mediator-version 3> + set mediator-priority vendor> + diff --git a/build/python313/meson/build.sh b/build/python313/meson/build.sh new file mode 100755 index 0000000000..a87b562ada --- /dev/null +++ b/build/python313/meson/build.sh @@ -0,0 +1,37 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/meson-313 +PROG=meson +inherit_ver python312/meson +SUMMARY="The Meson Build system" +DESC="An open source build system meant to be both extremely fast, " +DESC+="and, even more importantly, as user friendly as possible" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/meson/local.mog b/build/python313/meson/local.mog new file mode 100644 index 0000000000..a7d84efb47 --- /dev/null +++ b/build/python313/meson/local.mog @@ -0,0 +1,25 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +license COPYING license=Apache2 + + set pkg.depend.bypass-generate .* > + set pkg.depend.bypass-generate .* > + set pkg.depend.bypass-generate .* > + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + + drop> + diff --git a/build/python313/meson/patches/compiler_def_static_linker.patch b/build/python313/meson/patches/compiler_def_static_linker.patch new file mode 100644 index 0000000000..f5f9bc82f7 --- /dev/null +++ b/build/python313/meson/patches/compiler_def_static_linker.patch @@ -0,0 +1,24 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/mesonbuild/compilers/compilers.py a/mesonbuild/compilers/compilers.py +--- a~/mesonbuild/compilers/compilers.py 1970-01-01 00:00:00 ++++ a/mesonbuild/compilers/compilers.py 1970-01-01 00:00:00 +@@ -1107,7 +1107,7 @@ class Compiler(HoldableObject, metaclass + + def get_largefile_args(self) -> T.List[str]: + '''Enable transparent large-file-support for 32-bit UNIX systems''' +- if not (self.get_argument_syntax() == 'msvc' or self.info.is_darwin()): ++ if not (self.get_argument_syntax() == 'msvc' or self.info.is_darwin() or self.info.is_sunos()): + # Enable large-file support unconditionally on all platforms other + # than macOS and MSVC. macOS is now 64-bit-only so it doesn't + # need anything special, and MSVC doesn't have automatic LFS. +diff -wpruN --no-dereference '--exclude=*.orig' a~/mesonbuild/linkers/detect.py a/mesonbuild/linkers/detect.py +--- a~/mesonbuild/linkers/detect.py 1970-01-01 00:00:00 ++++ a/mesonbuild/linkers/detect.py 1970-01-01 00:00:00 +@@ -21,7 +21,7 @@ if T.TYPE_CHECKING: + from ..mesonlib import MachineChoice + + defaults: T.Dict[str, T.List[str]] = {} +-defaults['static_linker'] = ['ar', 'gar'] ++defaults['static_linker'] = ['gar', 'ar'] + defaults['vs_static_linker'] = ['lib'] + defaults['clang_cl_static_linker'] = ['llvm-lib'] + defaults['cuda_static_linker'] = ['nvlink'] diff --git a/build/python313/meson/patches/series b/build/python313/meson/patches/series new file mode 100644 index 0000000000..742308fe80 --- /dev/null +++ b/build/python313/meson/patches/series @@ -0,0 +1 @@ +compiler_def_static_linker.patch diff --git a/build/python313/orjson/build.sh b/build/python313/orjson/build.sh new file mode 100755 index 0000000000..c91811dc59 --- /dev/null +++ b/build/python313/orjson/build.sh @@ -0,0 +1,51 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/orjson-313 +PROG=orjson +inherit_ver python312/orjson +SUMMARY="orjson" +DESC="A fast, correct JSON library for Python." + +. $SRCDIR/../common.sh + +PATH+=:$OOCEBIN + +install() { + logmsg "Installing" + pushd $TMPDIR/$BUILDDIR >/dev/null + + logcmd mkdir -p $DESTDIR/$PYTHONVENDOR || logerr "mkdir" + logcmd cp target/release/lib$PROG.so \ + $DESTDIR/$PYTHONVENDOR/$PROG.cpython-$PYTHONPKGVER.so \ + || logerr "cp failed" + + popd >/dev/null +} + +init +download_source pymodules/$PROG $VER +patch_source +prep_build +build_rust +install +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/orjson/local.mog b/build/python313/orjson/local.mog new file mode 100644 index 0000000000..d3a95a8855 --- /dev/null +++ b/build/python313/orjson/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE-MIT license=MIT + diff --git a/build/python313/packaging/build.sh b/build/python313/packaging/build.sh new file mode 100755 index 0000000000..2770a33e14 --- /dev/null +++ b/build/python313/packaging/build.sh @@ -0,0 +1,37 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/packaging-313 +PROG=packaging +inherit_ver python312/packaging +SUMMARY="Core utilities for Python packages" +DESC="Reusable core utilities for various Python Packaging interoperability " +DESC+="specifications" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/packaging/local.mog b/build/python313/packaging/local.mog new file mode 100644 index 0000000000..6050e3f7cf --- /dev/null +++ b/build/python313/packaging/local.mog @@ -0,0 +1,13 @@ +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.BSD license=simplified-BSD + diff --git a/build/python313/patches/asyncio-watcher.patch b/build/python313/patches/asyncio-watcher.patch new file mode 100644 index 0000000000..a98f40afcb --- /dev/null +++ b/build/python313/patches/asyncio-watcher.patch @@ -0,0 +1,18 @@ +Asyncio watcher 'MultiLoopChildWatcher' currently doesn't work well +on Solaris and can freeze the event loop indefinitely. + +This was reported upstream: +https://bugs.python.org/issue37573 + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/asyncio/unix_events.py a/Lib/asyncio/unix_events.py +--- a~/Lib/asyncio/unix_events.py 1970-01-01 00:00:00 ++++ a/Lib/asyncio/unix_events.py 1970-01-01 00:00:00 +@@ -30,7 +30,7 @@ __all__ = ( + 'SelectorEventLoop', + 'AbstractChildWatcher', 'SafeChildWatcher', + 'FastChildWatcher', 'PidfdChildWatcher', +- 'MultiLoopChildWatcher', 'ThreadedChildWatcher', ++ 'ThreadedChildWatcher', + 'DefaultEventLoopPolicy', + 'EventLoop', + ) diff --git a/build/python313/patches/autoconf-macros.patch b/build/python313/patches/autoconf-macros.patch new file mode 100644 index 0000000000..2efc598627 --- /dev/null +++ b/build/python313/patches/autoconf-macros.patch @@ -0,0 +1,17 @@ + +As of version 3.9.3, python stopped bundling some autoconf m4 macros and +started relying on the 'autoconf-archive' package being installed and +in standard system paths. Yes, in a minor release update, really. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/configure.ac a/configure.ac +--- a~/configure.ac 1970-01-01 00:00:00 ++++ a/configure.ac 1970-01-01 00:00:00 +@@ -16,6 +16,8 @@ AC_PREREQ([2.71]) + + AC_INIT([python],[PYTHON_VERSION],[https://github.com/python/cpython/issues/]) + ++AC_CONFIG_MACRO_DIRS([/opt/ooce/autoconf-archive/share/aclocal]) ++ + m4_ifdef( + [AX_C_FLOAT_WORDS_BIGENDIAN], + [], diff --git a/build/python313/patches/cgiserver.patch b/build/python313/patches/cgiserver.patch new file mode 100644 index 0000000000..d84d921736 --- /dev/null +++ b/build/python313/patches/cgiserver.patch @@ -0,0 +1,45 @@ +Fixes Python CGI being confused about binary files (bugs 31546357 & 31936635). + +Upstream issue: +https://bugs.python.org/issue27777 + +WIP patch taken from upstream is still buggy, so we use +this in-house developed one. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/cgi.py a/Lib/cgi.py +--- a~/Lib/cgi.py 1970-01-01 00:00:00 ++++ a/Lib/cgi.py 1970-01-01 00:00:00 +@@ -705,7 +705,10 @@ class FieldStorage: + if not data: + self.done = -1 + break +- self.file.write(data) ++ if self._binary_file: ++ self.file.write(data) # keepindent ++ else: ++ self.file.write(data.decode()) + todo = todo - len(data) + + def read_lines(self): +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_cgi.py a/Lib/test/test_cgi.py +--- a~/Lib/test/test_cgi.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_cgi.py 1970-01-01 00:00:00 +@@ -389,6 +389,18 @@ Larry + self.assertEqual(fs.list[0].name, 'submit-name') + self.assertEqual(fs.list[0].value, 'Larry') + ++ def test_content_length_no_content_disposition(self): ++ body = b'{"test":123}' ++ env = { ++ 'CONTENT_LENGTH': len(body), ++ 'REQUEST_METHOD': 'POST', ++ 'CONTENT_TYPE': 'application/json', ++ 'wsgi.input': BytesIO(body), ++ } ++ ++ form = cgi.FieldStorage(fp=env['wsgi.input'], environ=env) ++ self.assertEqual(form.file.read(), body.decode(form.encoding)) ++ + def test_field_storage_multipart_no_content_length(self): + fp = BytesIO(b"""--MyBoundary + Content-Disposition: form-data; name="my-arg"; filename="foo" diff --git a/build/python313/patches/default-lib-path.patch b/build/python313/patches/default-lib-path.patch new file mode 100644 index 0000000000..e9de63e9b9 --- /dev/null +++ b/build/python313/patches/default-lib-path.patch @@ -0,0 +1,79 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/ctypes/util.py a/Lib/ctypes/util.py +--- a~/Lib/ctypes/util.py 1970-01-01 00:00:00 ++++ a/Lib/ctypes/util.py 1970-01-01 00:00:00 +@@ -239,43 +239,56 @@ elif os.name == "posix": + elif sys.platform == "sunos5": + + def _findLib_crle(name, is64): +- if not os.path.exists('/usr/bin/crle'): +- return None +- + env = dict(os.environ) + env['LC_ALL'] = 'C' + ++ paths = [] ++ + if is64: +- args = ('/usr/bin/crle', '-64') ++ var = 'LD_LIBRARY_PATH_64' + else: +- args = ('/usr/bin/crle',) ++ var = 'LD_LIBRARY_PATH_32' ++ ++ if (lp := env.get(var)) or (lp := env.get('LD_LIBRARY_PATH')): ++ paths.extend(lp.split(':')) ++ ++ if os.path.exists('/usr/bin/crle'): ++ args = ['/usr/bin/crle'] ++ if is64: ++ args.append('-64') ++ var = 'LD_CONFIG_64' ++ else: ++ var = 'LD_CONFIG_32' ++ ++ if (cfg := env.get(var)) or (cfg := env.get('LD_CONFIG')): ++ args.extend(['-c', cfg]) + +- paths = None + try: +- proc = subprocess.Popen(args, +- stdout=subprocess.PIPE, +- stderr=subprocess.DEVNULL, +- env=env) ++ with subprocess.Popen(args, ++ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, ++ env=env) as proc: ++ for line in proc.stdout: #WS ++ line = line.strip() #WS ++ if line.startswith( ++ b'Default Library Path (ELF):'): ++ paths.extend( ++ os.fsdecode(line).split()[4].split(':')) ++ break + except OSError: # E.g. bad executable +- return None +- with proc: +- for line in proc.stdout: +- line = line.strip() +- if line.startswith(b'Default Library Path (ELF):'): +- paths = os.fsdecode(line).split()[4] ++ pass + + if not paths: + return None + +- for dir in paths.split(":"): +- libfile = os.path.join(dir, "lib%s.so" % name) ++ for dir in paths: ++ libfile = os.path.join(dir, f'lib{name}.so') + if os.path.exists(libfile): + return libfile + + return None + + def find_library(name, is64 = False): +- return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name)) ++ return _get_soname(_findLib_crle(name, is64)) + + else: + diff --git a/build/python313/patches/disable_epoll.patch b/build/python313/patches/disable_epoll.patch new file mode 100644 index 0000000000..d1706bc9cd --- /dev/null +++ b/build/python313/patches/disable_epoll.patch @@ -0,0 +1,23 @@ + +Without this patch, python detects and uses epoll which only exists in +OmniOS for lx zones and Linux compatibility. It is not quite the same as +the Linux implementation and can cause socket related failures in python. + +There is no nice way to tell configure that we don't have it +(pkgsrc get around this by installing a broken epoll.h into the build + chroot area). + +diff -wpruN --no-dereference '--exclude=*.orig' a~/configure.ac a/configure.ac +--- a~/configure.ac 1970-01-01 00:00:00 ++++ a/configure.ac 1970-01-01 00:00:00 +@@ -5170,8 +5170,8 @@ PY_CHECK_FUNC([symlink], [@%:@include ]) + PY_CHECK_FUNC([fsync], [@%:@include ]) + PY_CHECK_FUNC([fdatasync], [@%:@include ]) +-PY_CHECK_FUNC([epoll_create], [@%:@include ], [HAVE_EPOLL]) +-PY_CHECK_FUNC([epoll_create1], [@%:@include ]) ++PY_CHECK_FUNC([NOepoll_create], [@%:@include ], [HAVE_EPOLL]) ++PY_CHECK_FUNC([NOepoll_create1], [@%:@include ]) + PY_CHECK_FUNC([kqueue],[ + #include + #include diff --git a/build/python313/patches/dont-use-ccs.patch b/build/python313/patches/dont-use-ccs.patch new file mode 100644 index 0000000000..1e65c6af7f --- /dev/null +++ b/build/python313/patches/dont-use-ccs.patch @@ -0,0 +1,12 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/ctypes/util.py a/Lib/ctypes/util.py +--- a~/Lib/ctypes/util.py 1970-01-01 00:00:00 ++++ a/Lib/ctypes/util.py 1970-01-01 00:00:00 +@@ -168,7 +168,7 @@ elif os.name == "posix": + return None + + try: +- proc = subprocess.Popen(("/usr/ccs/bin/dump", "-Lpv", f), ++ proc = subprocess.Popen(("/usr/bin/dump", "-Lpv", f), + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL) + except OSError: # E.g. command not found diff --git a/build/python313/patches/encoding-alias.patch b/build/python313/patches/encoding-alias.patch new file mode 100644 index 0000000000..28ec84b43d --- /dev/null +++ b/build/python313/patches/encoding-alias.patch @@ -0,0 +1,38 @@ +Add missing encoding aliases. It may be contributed upstream at some point, +but the suitability (or lack thereof) has not yet been determined. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/encodings/aliases.py a/Lib/encodings/aliases.py +--- a~/Lib/encodings/aliases.py 1970-01-01 00:00:00 ++++ a/Lib/encodings/aliases.py 1970-01-01 00:00:00 +@@ -79,6 +79,7 @@ aliases = { + + # cp1251 codec + '1251' : 'cp1251', ++ 'ansi_1251' : 'cp1251', + 'windows_1251' : 'cp1251', + + # cp1252 codec +@@ -234,6 +235,7 @@ aliases = { + 'u_jis' : 'euc_jp', + + # euc_kr codec ++ '5601' : 'euc_kr', + 'euckr' : 'euc_kr', + 'korean' : 'euc_kr', + 'ksc5601' : 'euc_kr', +@@ -484,6 +486,7 @@ aliases = { + 'shiftjis' : 'shift_jis', + 'sjis' : 'shift_jis', + 's_jis' : 'shift_jis', ++ 'pck' : 'shift_jis', + + # shift_jis_2004 codec + 'shiftjis2004' : 'shift_jis_2004', +@@ -500,6 +503,7 @@ aliases = { + 'tis_620_0' : 'tis_620', + 'tis_620_2529_0' : 'tis_620', + 'tis_620_2529_1' : 'tis_620', ++ 'tis620.2533' : 'tis_620', + 'iso_ir_166' : 'tis_620', + + # utf_16 codec diff --git a/build/python313/patches/gethostbyname.patch b/build/python313/patches/gethostbyname.patch new file mode 100644 index 0000000000..554af30301 --- /dev/null +++ b/build/python313/patches/gethostbyname.patch @@ -0,0 +1,42 @@ +Attempting to detect whether we have a gethostbyname_r() with 6 arguments +is fatal with gcc14. We jump straight to the 5 argument check which is +correct when building with XPG6. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/configure.ac a/configure.ac +--- a~/configure.ac 1970-01-01 00:00:00 ++++ a/configure.ac 1970-01-01 00:00:00 +@@ -5745,26 +5745,8 @@ AH_TEMPLATE([HAVE_GETHOSTBYNAME_R], + + AC_CHECK_FUNC([gethostbyname_r], + [AC_DEFINE([HAVE_GETHOSTBYNAME_R]) +- AC_MSG_CHECKING([gethostbyname_r with 6 args]) + OLD_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" +- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +-# include +- ]], [[ +- char *name; +- struct hostent *he, *res; +- char buffer[2048]; +- int buflen = 2048; +- int h_errnop; +- +- (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop) +- ]])],[ +- AC_DEFINE([HAVE_GETHOSTBYNAME_R]) +- AC_DEFINE([HAVE_GETHOSTBYNAME_R_6_ARG], [1], +- [Define this if you have the 6-arg version of gethostbyname_r().]) +- AC_MSG_RESULT([yes]) +- ],[ +- AC_MSG_RESULT([no]) + AC_MSG_CHECKING([gethostbyname_r with 5 args]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + # include +@@ -5803,7 +5785,6 @@ AC_CHECK_FUNC([gethostbyname_r], + AC_MSG_RESULT([no]) + ]) + ]) +- ]) + CFLAGS=$OLD_CFLAGS + ], [ + AC_CHECK_FUNCS([gethostbyname]) diff --git a/build/python313/patches/illumos.patch b/build/python313/patches/illumos.patch new file mode 100644 index 0000000000..59b01a69cc --- /dev/null +++ b/build/python313/patches/illumos.patch @@ -0,0 +1,59 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/configure.ac a/configure.ac +--- a~/configure.ac 1970-01-01 00:00:00 ++++ a/configure.ac 1970-01-01 00:00:00 +@@ -317,6 +317,7 @@ then + # ac_sys_system and ac_sys_release are used for setting + # a lot of different things including 'define_xopen_source' + # in the case statement below. ++ ac_sys_release= + case "$host" in + *-*-linux-android*) + ac_sys_system=Linux-android +@@ -339,12 +340,15 @@ then + *-*-wasi*) + ac_sys_system=WASI + ;; ++ *-*-solaris*) ++ ac_sys_system=SunOS ++ ac_sys_release=5.11 ++ ;; + *) + # for now, limit cross builds to known configurations + MACHDEP="unknown" + AC_MSG_ERROR([cross build not supported for $host]) + esac +- ac_sys_release= + else + ac_sys_system=`uname -s` + if test "$ac_sys_system" = "AIX" \ +@@ -452,6 +456,15 @@ AC_ARG_ENABLE([universalsdk], + UNIVERSALSDK= + enable_universalsdk= + ;; ++ *-*-solaris*) ++ case "$host_cpu" in ++ aarch64*) ++ _host_cpu=arm ++ ;; ++ *) ++ _host_cpu=$host_cpu ++ esac ++ ;; + *) + UNIVERSALSDK=$enableval + if test ! -d "${UNIVERSALSDK}" +@@ -777,6 +790,14 @@ if test "$cross_compiling" = yes; then + wasm32-*-* | wasm64-*-*) + _host_ident=$host_cpu + ;; ++ *-*-solaris2) ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=aarch64-unknown-solaris2 ;; ++ *) ++ AC_MSG_ERROR([unknown illumos platform]) ;; ++ esac ++ ;; + *) + # for now, limit cross builds to known configurations + MACHDEP="unknown" diff --git a/build/python313/patches/locale-encoding.patch b/build/python313/patches/locale-encoding.patch new file mode 100644 index 0000000000..42484a92d9 --- /dev/null +++ b/build/python313/patches/locale-encoding.patch @@ -0,0 +1,104 @@ +Python on Solaris doesn't handle non UTF-8 locales because of the way they are +encoded. The wchar_t encoding used for stored symbols is not standardized. While +on Linux symbols from all encodings will be mapped to their UTF-8 values, this +is not the case on Solaris, where only UTF-8 locales work like that; other +encodings can use any arbitrary value. Since Python expects no value to be +higher than the maximum valid code point in Unicode (which is U+10FFFF), it +breaks on Solaris when non UTF-8 locale is used. See bug 31790476. + +To fix this, we have to convert given wchar_t to utf32 each time locale is not +UTF-8 encoded (or ASCII, which can safely be ignored). + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Include/unicodeobject.h a/Include/unicodeobject.h +--- a~/Include/unicodeobject.h 1970-01-01 00:00:00 ++++ a/Include/unicodeobject.h 1970-01-01 00:00:00 +@@ -89,6 +89,11 @@ Copyright (c) Corporation for National R + # endif + #endif + ++#if defined(__sun) && defined(__SVR4) ++# include ++# include ++#endif ++ + /* Py_UCS4 and Py_UCS2 are typedefs for the respective + unicode representations. */ + typedef uint32_t Py_UCS4; +diff -wpruN --no-dereference '--exclude=*.orig' a~/Objects/unicodeobject.c a/Objects/unicodeobject.c +--- a~/Objects/unicodeobject.c 1970-01-01 00:00:00 ++++ a/Objects/unicodeobject.c 1970-01-01 00:00:00 +@@ -1956,6 +1956,15 @@ unicode_char(Py_UCS4 ch) + return unicode; + } + ++#if defined(__sun) && defined(__SVR4) ++/* Detect whether currently used locale uses UTF compatible encoding. */ ++int codeset_is_utf8_compatible() ++{ ++ char* res = nl_langinfo(CODESET); ++ return !(strcmp(res, "UTF-8") && strcmp(res, "646")); ++} ++#endif ++ + PyObject * + PyUnicode_FromWideChar(const wchar_t *u, Py_ssize_t size) + { +@@ -1992,6 +2001,58 @@ PyUnicode_FromWideChar(const wchar_t *u, + return unicode; + } + #endif ++ ++#if defined(__sun) && defined(__SVR4) ++ /* Check whether current locale uses UTF to encode symbols */ ++ if (!codeset_is_utf8_compatible()) { ++ ++ /* Given 'u' might not be NULL terminated (size smaller than its ++ length); copy and terminate part we are interested in. */ ++ wchar_t* substr = PyMem_RawMalloc((size + 1) * sizeof(wchar_t)); ++ memcpy(substr, u, size * sizeof(wchar_t)); ++ substr[size] = 0; ++ ++ /* Convert given wide-character string to a character string */ ++ size_t buffsize = wcstombs(NULL, substr, 0) + 1; ++ if (buffsize == (size_t)-1) { ++ PyMem_RawFree(substr); ++ PyErr_Format(PyExc_ValueError, "wcstombs() conversion failed"); ++ return NULL; ++ } ++ ++ char* buffer = PyMem_RawMalloc(buffsize * sizeof(char)); ++ size_t res = wcstombs(buffer, substr, buffsize); ++ assert(res == buffsize - 1); ++ ++ /* Convert character string to UTF32 encoded char32_t string. ++ Since wchar_t and char32_t have the same size on Solaris and one ++ wchar_t symbol corresponds to one UTF32 value, we can safely ++ reuse this buffer and skip additional allocation. */ ++ char32_t* c32 = (char32_t*) substr; ++ mbstate_t state = {0}; ++ ++ int i = 0; ++ char* ptr = buffer; ++ char* end = ptr + res + 1; ++ while (res = mbrtoc32(&(c32[i]), ptr, end - ptr, &state)) { ++ if (res == (size_t)-1 || res == (size_t)-2 || res == (size_t)-3) { ++ PyMem_RawFree(c32); ++ PyMem_RawFree(buffer); ++ PyErr_Format(PyExc_ValueError, ++ "mbrtoc32() conversion failed with error code: %d", ++ res); ++ return NULL; ++ } ++ ptr += res; ++ i ++; ++ } ++ PyMem_RawFree(buffer); ++ ++ PyObject *unicode = _PyUnicode_FromUCS4(c32, size); ++ PyMem_RawFree(c32); ++ return unicode; ++ } ++#endif + + /* Single character Unicode objects in the Latin-1 range are + shared when using this constructor */ diff --git a/build/python313/patches/mod-posix-sched_priority.patch b/build/python313/patches/mod-posix-sched_priority.patch new file mode 100644 index 0000000000..4df62a2094 --- /dev/null +++ b/build/python313/patches/mod-posix-sched_priority.patch @@ -0,0 +1,33 @@ + +On illumos, scheduling priorities can be less than 0 +(For example, the default range is -60 to 60 for the TS and FSS schedulers) + +However, -1 alongside EINVAL represents an error. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/posixmodule.c a/Modules/posixmodule.c +--- a~/Modules/posixmodule.c 1970-01-01 00:00:00 ++++ a/Modules/posixmodule.c 1970-01-01 00:00:00 +@@ -8097,7 +8097,11 @@ os_sched_get_priority_max_impl(PyObject + int max; + + max = sched_get_priority_max(policy); ++#ifdef __sun ++ if (max == -1 && errno == EINVAL) ++#else + if (max < 0) ++#endif + return posix_error(); + return PyLong_FromLong(max); + } +@@ -8116,7 +8120,11 @@ os_sched_get_priority_min_impl(PyObject + /*[clinic end generated code: output=7595c1138cc47a6d input=21bc8fa0d70983bf]*/ + { + int min = sched_get_priority_min(policy); ++#ifdef __sun ++ if (min == -1 && errno == EINVAL) ++#else + if (min < 0) ++#endif + return posix_error(); + return PyLong_FromLong(min); + } diff --git a/build/python313/patches/mod-shutil-sendfile.patch b/build/python313/patches/mod-shutil-sendfile.patch new file mode 100644 index 0000000000..69eff3afb5 --- /dev/null +++ b/build/python313/patches/mod-shutil-sendfile.patch @@ -0,0 +1,17 @@ + +Without this patch, shutil.copyfile() will only use sendfile() on Linux +It works on illumos too, and this fixes a problem with tests that rely +on sendfile being involved. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/shutil.py a/Lib/shutil.py +--- a~/Lib/shutil.py 1970-01-01 00:00:00 ++++ a/Lib/shutil.py 1970-01-01 00:00:00 +@@ -48,7 +48,7 @@ COPY_BUFSIZE = 1024 * 1024 if _WINDOWS e + # This should never be removed, see rationale in: + # https://bugs.python.org/issue43743#msg393429 + _USE_CP_SENDFILE = (hasattr(os, "sendfile") +- and sys.platform.startswith(("linux", "android"))) ++ and sys.platform.startswith(("linux", "android", "sunos"))) + _HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS + + # CMD defaults in Windows 10 diff --git a/build/python313/patches/module-dlpi.patch b/build/python313/patches/module-dlpi.patch new file mode 100644 index 0000000000..d640a525bd --- /dev/null +++ b/build/python313/patches/module-dlpi.patch @@ -0,0 +1,1346 @@ +This patch provides Python dlpi support. It may be contributed upstream at +some point, but the suitability (or lack thereof) has not yet been determined. +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/dlpitest.py a/Lib/test/dlpitest.py +--- a~/Lib/test/dlpitest.py 1970-01-01 00:00:00 ++++ a/Lib/test/dlpitest.py 1970-01-01 00:00:00 +@@ -0,0 +1,96 @@ ++#!/usr/bin/python3 ++ ++import dlpi ++import sys ++import time ++import struct ++ ++#test listlink ++linklist = dlpi.listlink() ++print("Found %d links:" % len(linklist)) ++print(linklist) ++ ++#pick up the first data link for below testing ++linkname = linklist[0] ++ ++#open link ++print("opening link: " + linkname + "...") ++testlink = dlpi.link(linkname) ++ ++#read some info of testlink ++print("linkname is %s" % testlink.get_linkname()) ++print("link fd is %d" % testlink.get_fd()) ++mactype = testlink.get_mactype() ++print("dlpi mactype is %d" % mactype) ++print("after convert:") ++print("\tmactype is %s" % dlpi.mactype(mactype)) ++print("\tiftype is %d" % dlpi.iftype(mactype)) ++print("\tarptype is %d" % dlpi.arptype(mactype)) ++bcastaddr = testlink.get_bcastaddr() ++print("broadcast addr is: ", end=' ') ++print(struct.unpack("BBBBBB",bcastaddr)) ++physaddr = testlink.get_physaddr(dlpi.FACT_PHYS_ADDR) ++print("factory physical address is: ", end=' ') ++print(struct.unpack("BBBBBB",physaddr)) ++print("current timeout value is %d" % testlink.get_timeout()) ++print("sdu is:", end=' ') ++print(testlink.get_sdu()) ++print("qos select is:", end=' ') ++print(testlink.get_qos_select()) ++print("qos range is:", end=' ') ++print(testlink.get_qos_range()) ++ ++#set some config value of testlink and read them again ++print("setting current physical addr to aa:0:10:13:27:5") ++testlink.set_physaddr(b"\xaa\0\x10\x13\x27\5") ++physaddr = testlink.get_physaddr(dlpi.CURR_PHYS_ADDR) ++print("current physical addr is: ", end=' ') ++print(struct.unpack("BBBBBB",physaddr)) ++print("set timeout value to 6...") ++testlink.set_timeout(6) ++print("timeout value is %d" % testlink.get_timeout()) ++ ++#test enable/disable multicast ++print("enable/disable multicast address 1:0:5e:0:0:5") ++testlink.enabmulti('\1\0\x5e\0\0\5') ++testlink.disabmulti('\1\0\x5e\0\0\5') ++ ++#test bind ++print("binding to SAP 0x9000...") ++testlink.bind(0x9000) ++print("sap is %x" % testlink.get_sap()) ++print("state is: %d" % testlink.get_state()) ++ ++#test send ++print("sending broadcast loopback packet...") ++testlink.send(bcastaddr, '\0\1\2\3\4\5') ++ ++#test notify functionality ++arg = "notification callback arg" ++def notify(arg, notes, value): ++ print("NOTE_PROMISC_ON_PHYS notification received with arg: '%s'" % arg) ++print("enabled notification on NOTE_PROMISC_ON_PHYS") ++id = testlink.enabnotify(dlpi.NOTE_PROMISC_ON_PHYS, notify, arg) #enable notification ++testlink.promiscon() #trigger the event (will be seen while receiving pkt below) ++ ++#test receive ++print("testing receiving...") ++try: ++ testlink.recv(0, 0) #should see NOTE_PROMISC_ON_PHYS event here ++except dlpi.error as err: ++ errnum, errinfo = err ++ if errnum == 10006: ++ pass #timeout error is expected here ++ else: #test fails if reach here ++ print("test failed", end=' ') ++ print(errnum, end=' ') ++ print(err) ++ ++testlink.promiscoff() ++testlink.disabnotify(id) #disable notification ++ ++#test unbind ++print("unbinding...") ++testlink.unbind() ++print("sap is %x" % testlink.get_sap()) ++print("state is: %d" % testlink.get_state()) +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/Setup.local a/Modules/Setup.local +--- a~/Modules/Setup.local 1970-01-01 00:00:00 ++++ a/Modules/Setup.local 1970-01-01 00:00:00 +@@ -1,3 +1,4 @@ + # Edit this file for local setup changes + + ucred ucred.c -ltsol ++dlpi dlpimodule.c -ldlpi +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/dlpimodule.c a/Modules/dlpimodule.c +--- a~/Modules/dlpimodule.c 1970-01-01 00:00:00 ++++ a/Modules/dlpimodule.c 1970-01-01 00:00:00 +@@ -0,0 +1,1232 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. ++ */ ++ ++#define PY_SSIZE_T_CLEAN ++ ++#include ++#include ++#include ++ ++typedef struct { ++ PyObject_HEAD ++ dlpi_handle_t dlpihdl; ++} pylink_t; ++ ++typedef struct { ++ PyObject *pyfunc; ++ PyObject *pyarg; ++} callback_data_t; ++ ++/* ++ * dlpi_err: the only exception raised for libdlpi related error. ++ * The accompanying value is: ++ * (dlpi_error_number, string), when it's a dlpi specific error, ++ * or, (DL_SYSERR, errno, string), when it's coming from a system call. ++ */ ++static PyObject *dlpi_err; ++ ++static void ++dlpi_raise_exception(int err) ++{ ++ PyObject *e = NULL; ++ ++ if (err == DL_SYSERR) { ++ e = Py_BuildValue("(iis)", DL_SYSERR, errno, strerror(errno)); ++ } else { ++ e = Py_BuildValue("(is)", err, dlpi_strerror(err)); ++ } ++ if (e != NULL) { ++ PyErr_SetObject(dlpi_err, e); ++ Py_DECREF(e); ++ } ++} ++ ++PyDoc_STRVAR(link_doc, ++ "link(linkname[, flags]) -> link object\n" ++ "\n" ++ "Open linkname with specified flags.\n" ++ "Three flags are supported: PASSIVE, RAW, NATIVE.\n" ++ "And these flags can be bitwise-OR'ed together(default flag is 0).\n" ++ "You need sys_net_rawaccess privilege to open a link.\n" ++ "See dlpi_open(3DLPI).\n" ++); ++static int ++link_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ uint_t flags = 0; ++ dlpi_handle_t dh; ++ char *linkname; ++ int rval; ++ static char *keywords[] = {"linkname", "flags", NULL}; ++ pylink_t *link = (pylink_t *)self; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|I", keywords, ++ &linkname, &flags)) ++ return (-1); ++ ++ if ((rval = dlpi_open(linkname, &dh, flags)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (-1); ++ } ++ ++ link->dlpihdl = dh; ++ ++ return (0); ++} ++ ++static void ++link_dealloc(pylink_t *link) ++{ ++ if (link->dlpihdl != NULL) ++ dlpi_close(link->dlpihdl); ++ Py_TYPE(link)->tp_free((PyObject *)link); ++} ++ ++PyDoc_STRVAR(bind_doc, ++ "bind(sap) -> unsigned int\n" ++ "\n" ++ "Attempts to bind the link to specified SAP, or ANY_SAP.\n" ++ "Returns the SAP that the function actually bound to, which\n" ++ "could be different from the SAP requested.\n" ++ "See dlpi_bind(3DLPI).\n" ++); ++static PyObject * ++link_bind(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ uint_t sap = 0, boundsap = 0; ++ static char *keywords[] = {"sap", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", keywords, &sap)) ++ return (NULL); ++ ++ if ((rval = dlpi_bind(link->dlpihdl, sap, &boundsap)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I", boundsap)); ++} ++ ++PyDoc_STRVAR(unbind_doc, ++ "unbind() -> None\n" ++ "\n" ++ "Attempts to unbind the link from previously bound sap.\n" ++ "See dlpi_unbind(3DLPI).\n" ++); ++static PyObject * ++link_unbind(pylink_t *link) ++{ ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_unbind(link->dlpihdl)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(send_doc, ++ "send(destaddr, message[, sap, minpri, maxpri]) -> None\n" ++ "\n" ++ "Attempts to send message over this link to sap on destaddr.\n" ++ "If SAP is not specified, the bound SAP is used\n" ++ "You can also specify priority range (minpri, maxpri).\n" ++ "See dlpi_send(3DLPI).\n" ++); ++static PyObject * ++link_send(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ char *daddr = NULL, *msgbuf = NULL; ++ size_t daddrlen = 0, msglen = 0; ++ t_scalar_t minpri = DL_QOS_DONT_CARE, maxpri = DL_QOS_DONT_CARE; ++ uint_t sap = DLPI_ANY_SAP; ++ dlpi_sendinfo_t ds, *dsp = NULL; ++ static char *keywords[] = ++ {"destaddr", "message", "sap", "minpri", "maxpri", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "y#y#|Iii", keywords, ++ &daddr, &daddrlen, &msgbuf, &msglen, &sap, &minpri, &maxpri)) ++ return (NULL); ++ ++ if ((sap != DLPI_ANY_SAP) || (minpri != DL_QOS_DONT_CARE) || ++ (maxpri != DL_QOS_DONT_CARE)) { ++ ds.dsi_sap = sap; ++ ds.dsi_prio.dl_min = minpri; ++ ds.dsi_prio.dl_max = maxpri; ++ dsp = &ds; ++ } ++ ++ if ((rval = dlpi_send(link->dlpihdl, daddr, daddrlen, ++ msgbuf, msglen, dsp)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(recv_doc, ++ "recv(msglen[, timeout]) -> (string, string), or (None, None)\n" ++ "\n" ++ "Attempts to receive message over this link.\n" ++ "You need to specify the message length for the received message.\n" ++ "And you can specify timeout value in milliseconds.\n" ++ "The default timeout value is -1 (wait forever).\n" ++ "Returns (source address, message data), or (None, None) when error occurs.\n" ++ "See dlpi_recv(3DLPI).\n" ++); ++static PyObject * ++link_recv(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ PyObject *obj; ++ char *saddr = NULL, *msgbuf = NULL; ++ size_t saddrlen = 0, msglen = 0, *saddrlenp = NULL, *msglenp = NULL; ++ int msec = -1; /* block until receive data */ ++ static char *keywords[] = {"msglen", "timeout", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "k|i", ++ keywords, &msglen, &msec)) ++ return (NULL); ++ ++ if (msglen > 0) { ++ msgbuf = malloc(msglen); ++ if (msgbuf == NULL) { ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ saddrlen = DLPI_PHYSADDR_MAX; ++ saddr = malloc(saddrlen); ++ if (saddr == NULL) { ++ dlpi_raise_exception(DL_SYSERR); ++ free(msgbuf); ++ return (NULL); ++ } ++ msglenp = &msglen; ++ saddrlenp = &saddrlen; ++ } ++ ++ if ((rval = dlpi_recv(link->dlpihdl, saddr, saddrlenp, msgbuf, ++ msglenp, msec, NULL)) != DLPI_SUCCESS) { ++ if (msgbuf != NULL) ++ free(msgbuf); ++ if (saddr != NULL) ++ free(saddr); ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ obj = Py_BuildValue("y#y#", saddr, saddrlen, msgbuf, msglen); ++ if (msgbuf != NULL) ++ free(msgbuf); ++ if (saddr != NULL) ++ free(saddr); ++ return (obj); ++} ++ ++PyDoc_STRVAR(disabmulti_doc, ++ "disabmulti(address) -> None\n" ++ "\n" ++ "Disable a specified multicast address on this link.\n" ++ "See dlpi_disabmulti(3DLPI).\n" ++); ++static PyObject * ++link_disabmulti(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ char *addr = NULL; ++ size_t addrlen = 0; ++ static char *keywords[] = {"address", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "y#", keywords, ++ &addr, &addrlen)) ++ return (NULL); ++ ++ if ((addrlen == 0) || (addrlen > DLPI_PHYSADDR_MAX)) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_disabmulti(link->dlpihdl, addr, addrlen)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(enabmulti_doc, ++ "enabmulti(address) -> None\n" ++ "\n" ++ "Enable a specified multicast address on this link.\n" ++ "See dlpi_enabmulti(3DLPI).\n" ++); ++static PyObject * ++link_enabmulti(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ char *addr = NULL; ++ size_t addrlen = 0; ++ static char *keywords[] = {"address", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "y#", keywords, ++ &addr, &addrlen)) ++ return (NULL); ++ ++ if ((addrlen == 0) || (addrlen > DLPI_PHYSADDR_MAX)) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_enabmulti(link->dlpihdl, addr, addrlen)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++static void ++dlpi_callback(dlpi_handle_t hdl, dlpi_notifyinfo_t *ni, void *arg) ++{ ++ callback_data_t *cd = (callback_data_t *)arg; ++ PyObject *arglist, *result; ++ ++ switch (ni->dni_note) { ++ case DL_NOTE_SPEED: ++ arglist = Py_BuildValue("(OII)", ++ cd->pyarg, ni->dni_note, ni->dni_speed); ++ break; ++ case DL_NOTE_SDU_SIZE: ++ arglist = Py_BuildValue("(OII)", ++ cd->pyarg, ni->dni_note, ni->dni_size); ++ break; ++ case DL_NOTE_PHYS_ADDR: ++ arglist = Py_BuildValue("(OIy#)", ++ cd->pyarg, ni->dni_note, ni->dni_physaddr, ++ ni->dni_physaddrlen); ++ break; ++ default: ++ arglist = Py_BuildValue("(OIO)", cd->pyarg, ni->dni_note, ++ Py_None); ++ } ++ ++ result = PyObject_CallObject(cd->pyfunc, arglist); ++ Py_DECREF(arglist); ++ if (result == NULL) { ++ PyErr_Clear(); /* cannot raise error */ ++ } ++ Py_DECREF(result); ++ Py_DECREF(cd->pyfunc); ++ Py_XDECREF(cd->pyarg); ++ free(cd); ++} ++ ++PyDoc_STRVAR(enabnotify_doc, ++ "enabnotify(events, function[, arg]) -> unsigned long\n" ++ "\n" ++ "Enables a notification callback for the set of specified events,\n" ++ "which must be one or more (by a logical OR) events listed as below:\n" ++ "NOTE_LINK_DOWN Notify when link has gone down\n" ++ "NOTE_LINK_UP Notify when link has come up\n" ++ "NOTE_PHYS_ADDR Notify when address changes\n" ++ "NOTE_SDU_SIZE Notify when MTU changes\n" ++ "NOTE_SPEED Notify when speed changes\n" ++ "NOTE_PROMISC_ON_PHYS Notify when PROMISC_PHYS is set\n" ++ "NOTE_PROMISC_OFF_PHYS Notify when PROMISC_PHYS is cleared\n" ++ "Returns a handle for this registration.\n" ++ "See dlpi_enabnotify(3DLPI).\n" ++); ++static PyObject * ++link_enabnotify(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ PyObject *func = NULL, *arg = NULL; ++ callback_data_t *cd; ++ uint_t notes = 0; ++ static char *keywords[] = {"events", "function", "arg", NULL}; ++ dlpi_notifyid_t id; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "IO|O", ++ keywords, ¬es, &func, &arg)) ++ return (NULL); ++ ++ if (!PyCallable_Check(func)) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ cd = malloc(sizeof(callback_data_t)); ++ if (cd == NULL) { ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ Py_INCREF(func); ++ Py_XINCREF(arg); ++ cd->pyfunc = func; ++ cd->pyarg = arg; ++ ++ if ((rval = dlpi_enabnotify(link->dlpihdl, notes, dlpi_callback, ++ cd, &id)) != DLPI_SUCCESS) { ++ free(cd); ++ Py_DECREF(func); ++ Py_XDECREF(arg); ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("k", id)); ++} ++ ++PyDoc_STRVAR(disabnotify_doc, ++ "disabnotify(handle) -> argument object, or None\n" ++ "\n" ++ "Disables the notification registration associated with handle.\n" ++ "You should get this handle by calling enabnotify().\n" ++ "Returns the argument passed in when registering the callback, or None.\n" ++ "See dlpi_disabnotify(3DLPI).\n" ++); ++static PyObject * ++link_disabnotify(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ dlpi_notifyid_t id; ++ callback_data_t *arg; ++ PyObject *pyargsaved; ++ static char *keywords[] = {"handle", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "k", keywords, &id)) ++ return (NULL); ++ ++ if ((rval = dlpi_disabnotify(link->dlpihdl, id, (void **)&arg)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ /* clean up */ ++ pyargsaved = arg->pyarg; ++ Py_XINCREF(pyargsaved); ++ Py_XDECREF(arg->pyarg); ++ Py_DECREF(arg->pyfunc); ++ free(arg); ++ ++ if (pyargsaved != NULL) ++ return (pyargsaved); ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(get_sap_doc, ++ "get_sap() -> unsigned int\n" ++ "\n" ++ "Returns the sap bound to this link.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_sap(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I", info.di_sap)); ++} ++ ++PyDoc_STRVAR(get_fd_doc, ++ "get_fd() -> int\n" ++ "\n" ++ "Returns the integer file descriptor that can be used to directly\n" ++ "operate on the link.\n" ++ "See dlpi_fd(3DLPI).\n" ++); ++static PyObject * ++link_get_fd(pylink_t *link) ++{ ++ int fd; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((fd = dlpi_fd(link->dlpihdl)) == -1) { ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("i", fd)); ++} ++ ++PyDoc_STRVAR(get_linkname_doc, ++ "get_linkname() -> string\n" ++ "\n" ++ "Returns the name of the link.\n" ++ "See dlpi_linkname(3DLPI).\n" ++); ++static PyObject * ++link_get_linkname(pylink_t *link) ++{ ++ const char *name = NULL; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((name = dlpi_linkname(link->dlpihdl)) == NULL) { ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("s", name)); ++} ++ ++PyDoc_STRVAR(get_bcastaddr_doc, ++ "get_bcastaddr() -> string, or None\n" ++ "\n" ++ "Returns the broadcast address of the link.\n" ++ "Returns None if the broadcast address is empty.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_bcastaddr(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ if (info.di_bcastaddrlen == 0) { ++ Py_INCREF(Py_None); ++ return (Py_None); ++ } ++ ++ return (Py_BuildValue("y#", info.di_bcastaddr, info.di_bcastaddrlen)); ++} ++ ++PyDoc_STRVAR(get_physaddr_doc, ++ "get_physaddr(addrtype) -> string, or None\n" ++ "\n" ++ "Addrtype can be any one of the value listed below:\n" ++ "FACT_PHYS_ADDR Factory physical address\n" ++ "CURR_PHYS_ADDR Current physical address\n" ++ "Returns the corresponding physical address of the link.\n" ++ "See dlpi_get_physaddr(3DLPI).\n" ++); ++static PyObject * ++link_get_physaddr(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ char *addr[DLPI_PHYSADDR_MAX]; ++ size_t addrlen = DLPI_PHYSADDR_MAX; ++ static char *keywords[] = {"addrtype", NULL}; ++ uint_t type; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", keywords, &type)) ++ return (NULL); ++ ++ if ((rval = dlpi_get_physaddr(link->dlpihdl, type, addr, &addrlen)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("y#", addr, addrlen)); ++} ++ ++PyDoc_STRVAR(set_physaddr_doc, ++ "set_physaddr(address) -> None\n" ++ "\n" ++ "Sets the physical address of the link.\n" ++ "See dlpi_set_physaddr(3DLPI).\n" ++); ++static PyObject * ++link_set_physaddr(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ char *addr = NULL; ++ size_t addrlen = 0; ++ static char *keywords[] = {"address", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "y#", keywords, ++ &addr, &addrlen)) ++ return (NULL); ++ ++ if ((rval = dlpi_set_physaddr(link->dlpihdl, DL_CURR_PHYS_ADDR, ++ addr, addrlen)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(promiscon_doc, ++ "promiscon([level]) -> None\n" ++ "\n" ++ "Enables promiscuous mode for the link at levels:\n" ++ "PROMISC_PHYS Promiscuous mode at the physical level(default)\n" ++ "PROMISC_SAP Promiscuous mode at the SAP level\n" ++ "PROMISC_MULTI Promiscuous mode for all multicast addresses\n" ++ "\n" ++ "The level modifier (OR'd with level) is:\n" ++ "PROMISC_NOLOOP Do not loopback messages to the client\n" ++ "See dlpi_promiscon(3DLPI).\n" ++); ++static PyObject * ++link_promiscon(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ uint_t level = DL_PROMISC_PHYS; ++ static char *keywords[] = {"level", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I", keywords, &level)) ++ return (NULL); ++ ++ if ((rval = dlpi_promiscon(link->dlpihdl, level)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(promiscoff_doc, ++ "promiscoff([level]) -> None\n" ++ "\n" ++ "Disables promiscuous mode for the link at levels:\n" ++ "PROMISC_PHYS Promiscuous mode at the physical level(default)\n" ++ "PROMISC_SAP Promiscuous mode at the SAP level\n" ++ "PROMISC_MULTI Promiscuous mode for all multicast addresses\n" ++ "\n" ++ "The level modifier (OR'd with level) is:\n" ++ "PROMISC_NOLOOP Do not loopback messages to the client\n" ++ "See dlpi_promiscoff(3DLPI).\n" ++); ++static PyObject * ++link_promiscoff(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ uint_t level = DL_PROMISC_PHYS; ++ static char *keywords[] = {"level", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I", keywords, &level)) ++ return (NULL); ++ ++ if ((rval = dlpi_promiscoff(link->dlpihdl, level)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(get_timeout_doc, ++ "get_timeout() -> int\n" ++ "\n" ++ "Returns current time out value of the link.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_timeout(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("i", info.di_timeout)); ++} ++ ++PyDoc_STRVAR(get_mactype_doc, ++ "get_mactype() -> unsigned char\n" ++ "\n" ++ "Returns MAC type of the link.\n" ++ "See for the list of possible MAC types.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_mactype(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("B", info.di_mactype)); ++} ++ ++PyDoc_STRVAR(set_timeout_doc, ++ "set_timeout(timeout) -> None\n" ++ "\n" ++ "Sets time out value of the link (default value: DEF_TIMEOUT).\n" ++ "See dlpi_set_timeout(3DLPI).\n" ++); ++static PyObject * ++link_set_timeout(pylink_t *link, PyObject *args, PyObject *kwds) ++{ ++ int timeout = DLPI_DEF_TIMEOUT; ++ static char *keywords[] = {"timeout", NULL}; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", keywords, &timeout)) ++ return (NULL); ++ ++ if ((rval = dlpi_set_timeout(link->dlpihdl, timeout)) != DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ Py_INCREF(Py_None); ++ return (Py_None); ++} ++ ++PyDoc_STRVAR(get_sdu_doc, ++ "get_sdu() -> (unsigned int, unsigned int)\n" ++ "\n" ++ "Returns (min sdu, max sdu).\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_sdu(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("II", info.di_min_sdu, info.di_max_sdu)); ++} ++ ++PyDoc_STRVAR(get_state_doc, ++ "get_state() -> unsigned int\n" ++ "\n" ++ "Returns current state of the link (either UNBOUND or IDLE).\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_state(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I", info.di_state)); ++} ++ ++PyDoc_STRVAR(get_qos_select_doc, ++ "get_qos_select() -> (unsigned int, int, int, int)\n" ++ "\n" ++ "Returns (qos type, trans delay, priority, residul err).\n" ++ "Unsupported QOS parameters are set to UNKNOWN.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_qos_select(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("Iiiii", ++ info.di_qos_sel.dl_qos_type, ++ info.di_qos_sel.dl_trans_delay, ++ info.di_qos_sel.dl_priority, ++ info.di_qos_sel.dl_residual_error)); ++} ++ ++PyDoc_STRVAR(get_qos_range_doc, ++ "get_qos_range() -> \n" ++ " (unsigned int, (int, int), (int, int), (int, int), int)\n" ++ "\n" ++ "Returns (qos type, (trans delay target, trans delay accept),\n" ++ "(min priority, max priority), (min protection, max protection),\n" ++ "residual err).\n" ++ "Unsupported QOS range values are set to UNKNOWN.\n" ++ "See dlpi_info(3DLPI).\n" ++); ++static PyObject * ++link_get_qos_range(pylink_t *link) ++{ ++ dlpi_info_t info; ++ int rval; ++ ++ if (link->dlpihdl == NULL) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ if ((rval = dlpi_info(link->dlpihdl, &info, 0)) != ++ DLPI_SUCCESS) { ++ dlpi_raise_exception(rval); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I(ii)(ii)(ii)i", ++ info.di_qos_range.dl_qos_type, ++ info.di_qos_range.dl_trans_delay.dl_target_value, ++ info.di_qos_range.dl_trans_delay.dl_accept_value, ++ info.di_qos_range.dl_priority.dl_min, ++ info.di_qos_range.dl_priority.dl_max, ++ info.di_qos_range.dl_protection.dl_min, ++ info.di_qos_range.dl_protection.dl_max, ++ info.di_qos_range.dl_residual_error)); ++} ++ ++static PyMethodDef pylink_methods[] = { ++ {"bind", (PyCFunction)(uintptr_t)link_bind, METH_VARARGS|METH_KEYWORDS, ++ bind_doc}, ++ {"unbind", (PyCFunction)(uintptr_t)link_unbind, METH_NOARGS, ++ unbind_doc}, ++ {"send", (PyCFunction)(uintptr_t)link_send, METH_VARARGS|METH_KEYWORDS, ++ send_doc}, ++ {"recv", (PyCFunction)(uintptr_t)link_recv, METH_VARARGS|METH_KEYWORDS, ++ recv_doc}, ++ {"disabmulti", (PyCFunction)(uintptr_t)link_disabmulti, ++ METH_VARARGS|METH_KEYWORDS, disabmulti_doc}, ++ {"enabmulti", (PyCFunction)(uintptr_t)link_enabmulti, ++ METH_VARARGS|METH_KEYWORDS, enabmulti_doc}, ++ {"enabnotify", (PyCFunction)(uintptr_t)link_enabnotify, ++ METH_VARARGS|METH_KEYWORDS, enabnotify_doc}, ++ {"disabnotify", (PyCFunction)(uintptr_t)link_disabnotify, ++ METH_VARARGS|METH_KEYWORDS, disabnotify_doc}, ++ {"get_fd", (PyCFunction)(uintptr_t)link_get_fd, METH_NOARGS, ++ get_fd_doc}, ++ {"get_sap", (PyCFunction)(uintptr_t)link_get_sap, METH_NOARGS, ++ get_sap_doc}, ++ {"get_mactype", (PyCFunction)(uintptr_t)link_get_mactype, METH_NOARGS, ++ get_mactype_doc}, ++ {"get_linkname", (PyCFunction)(uintptr_t)link_get_linkname, ++ METH_NOARGS, get_linkname_doc}, ++ {"get_bcastaddr", (PyCFunction)(uintptr_t)link_get_bcastaddr, ++ METH_NOARGS, get_bcastaddr_doc}, ++ {"get_physaddr", (PyCFunction)(uintptr_t)link_get_physaddr, ++ METH_VARARGS|METH_KEYWORDS, get_physaddr_doc}, ++ {"set_physaddr", (PyCFunction)(uintptr_t)link_set_physaddr, ++ METH_VARARGS|METH_KEYWORDS, set_physaddr_doc}, ++ {"promiscon", (PyCFunction)(uintptr_t)link_promiscon, ++ METH_VARARGS|METH_KEYWORDS, promiscon_doc}, ++ {"promiscoff", (PyCFunction)(uintptr_t)link_promiscoff, ++ METH_VARARGS|METH_KEYWORDS, promiscoff_doc}, ++ {"get_timeout", (PyCFunction)(uintptr_t)link_get_timeout, ++ METH_NOARGS, get_timeout_doc}, ++ {"set_timeout", (PyCFunction)(uintptr_t)link_set_timeout, ++ METH_VARARGS|METH_KEYWORDS, set_timeout_doc}, ++ {"get_sdu", (PyCFunction)(uintptr_t)link_get_sdu, METH_NOARGS, ++ get_sdu_doc}, ++ {"get_state", (PyCFunction)(uintptr_t)link_get_state, METH_NOARGS, ++ get_state_doc}, ++ {"get_qos_select", (PyCFunction)(uintptr_t)link_get_qos_select, ++ METH_NOARGS, get_qos_select_doc}, ++ {"get_qos_range", (PyCFunction)(uintptr_t)link_get_qos_range, ++ METH_NOARGS, get_qos_range_doc}, ++ {NULL, NULL} ++}; ++ ++static PyTypeObject pylink_type = { ++ PyVarObject_HEAD_INIT(NULL, 0) /* Must fill in type value later */ ++ "dlpi.link", /* tp_name */ ++ sizeof(pylink_t), /* tp_basicsize */ ++ 0, /* tp_itemsize */ ++ (destructor)link_dealloc, /* tp_dealloc */ ++ 0, /* tp_print */ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_reserved */ ++ 0, /* tp_repr */ ++ 0, /* tp_as_number */ ++ 0, /* tp_as_sequence */ ++ 0, /* tp_as_mapping */ ++ 0, /* tp_hash */ ++ 0, /* tp_call */ ++ 0, /* tp_str */ ++ 0, /* tp_getattro */ ++ 0, /* tp_setattro */ ++ 0, /* tp_as_buffer */ ++ Py_TPFLAGS_DEFAULT, /* tp_flags */ ++ link_doc, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ pylink_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)link_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ PyType_GenericNew, /* tp_new */ ++ 0, /* tp_free */ ++ 0, /* tp_is_gc */ ++}; ++ ++PyDoc_STRVAR(arptype_doc, ++ "arptype(arptype) -> unsigned int\n" ++ "\n" ++ "Converts a DLPI MAC type to an ARP hardware type defined\n" ++ " in \n" ++ "See dlpi_arptype(3DLPI)\n" ++); ++static PyObject * ++arptype(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ static char *keywords[] = {"arptype", NULL}; ++ uint_t dlpityp, arptyp; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", keywords, &dlpityp)) ++ return (NULL); ++ ++ if ((arptyp = dlpi_arptype(dlpityp)) == 0) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I", arptyp)); ++} ++ ++PyDoc_STRVAR(iftype_doc, ++ "iftype(iftype) -> unsigned int\n" ++ "\n" ++ "Converts a DLPI MAC type to a BSD socket interface type\n" ++ "defined in \n" ++ "See dlpi_iftype(3DLPI)\n" ++); ++static PyObject * ++iftype(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ static char *keywords[] = {"iftype", NULL}; ++ uint_t dlpityp, iftyp; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", keywords, &dlpityp)) ++ return (NULL); ++ ++ if ((iftyp = dlpi_iftype(dlpityp)) == 0) { ++ errno = EINVAL; ++ dlpi_raise_exception(DL_SYSERR); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("I", iftyp)); ++} ++ ++PyDoc_STRVAR(mactype_doc, ++ "mactype(mactype) -> string\n" ++ "\n" ++ "Returns a string that describes the specified mactype.\n" ++ "Valid mac types are defined in .\n" ++ "See dlpi_mactype(3DLPI)\n" ++); ++static PyObject * ++mactype(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ static char *keywords[] = {"mactype", NULL}; ++ uint_t mactyp; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", keywords, &mactyp)) ++ return (NULL); ++ ++ return (Py_BuildValue("s", dlpi_mactype(mactyp))); ++} ++ ++static boolean_t ++link_walker(const char *name, void *arg) ++{ ++ PyObject *linkname; ++ PyObject *list = (PyObject *)arg; ++ ++ if ((list == NULL) || !PyList_Check(list)) ++ return (B_FALSE); ++ ++ linkname = Py_BuildValue("s", name); ++ if (PyList_Append(list, linkname) == -1) ++ return (B_TRUE); ++ ++ Py_DECREF(linkname); ++ return (B_FALSE); ++} ++ ++PyDoc_STRVAR(listlink_doc, ++ "listlink() -> list\n" ++ "\n" ++ "Returns a list containing link names of all links on the system.\n" ++); ++static PyObject * ++listlink(PyObject *self, PyObject *args) ++{ ++ PyObject *list; ++ ++ if ((list = PyList_New(0)) == NULL) ++ return (NULL); ++ ++ dlpi_walk(link_walker, list, 0); ++ return (list); ++} ++ ++static PyMethodDef dlpi_methods[] = { ++ {"arptype", (PyCFunction)(uintptr_t)arptype, METH_VARARGS|METH_KEYWORDS, ++ arptype_doc}, ++ {"iftype", (PyCFunction)(uintptr_t)iftype, METH_VARARGS|METH_KEYWORDS, ++ iftype_doc}, ++ {"mactype", (PyCFunction)(uintptr_t)mactype, METH_VARARGS|METH_KEYWORDS, ++ mactype_doc}, ++ {"listlink", listlink, METH_NOARGS, listlink_doc}, ++ {NULL} ++}; ++ ++PyMODINIT_FUNC ++PyInit_dlpi (void) ++{ ++ PyObject *mod; ++ ++ if (PyType_Ready(&pylink_type) < 0) ++ return NULL; ++ ++ static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ "dlpi", ++ NULL, ++ -1, ++ dlpi_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ }; ++ ++ mod = PyModule_Create(&moduledef); ++ if (mod == NULL) ++ return NULL; ++ ++ dlpi_err = PyErr_NewException("dlpi.error", NULL, NULL); ++ if (dlpi_err == NULL) ++ return NULL; ++ PyModule_AddObject(mod, "error", dlpi_err); ++ ++ Py_INCREF(&pylink_type); ++ PyModule_AddObject(mod, "link", (PyObject *)&pylink_type); ++ PyModule_AddIntConstant(mod, "PASSIVE", DLPI_PASSIVE); ++ PyModule_AddIntConstant(mod, "RAW", DLPI_RAW); ++ PyModule_AddIntConstant(mod, "NATIVE", DLPI_NATIVE); ++ PyModule_AddIntConstant(mod, "ANY_SAP", DLPI_ANY_SAP); ++ PyModule_AddIntConstant(mod, "DEF_TIMEOUT", DLPI_DEF_TIMEOUT); ++ PyModule_AddIntConstant(mod, "NOTE_LINK_DOWN", DL_NOTE_LINK_DOWN); ++ PyModule_AddIntConstant(mod, "NOTE_LINK_UP", DL_NOTE_LINK_UP); ++ PyModule_AddIntConstant(mod, "NOTE_PHYS_ADDR", DL_NOTE_PHYS_ADDR); ++ PyModule_AddIntConstant(mod, "NOTE_SDU_SIZE", DL_NOTE_SDU_SIZE); ++ PyModule_AddIntConstant(mod, "NOTE_SPEED", DL_NOTE_SPEED); ++ PyModule_AddIntConstant(mod, "NOTE_PROMISC_ON_PHYS", ++ DL_NOTE_PROMISC_ON_PHYS); ++ PyModule_AddIntConstant(mod, "NOTE_PROMISC_OFF_PHYS", ++ DL_NOTE_PROMISC_OFF_PHYS); ++ PyModule_AddIntConstant(mod, "FACT_PHYS_ADDR", DL_FACT_PHYS_ADDR); ++ PyModule_AddIntConstant(mod, "CURR_PHYS_ADDR", DL_CURR_PHYS_ADDR); ++ PyModule_AddIntConstant(mod, "PROMISC_PHYS", DL_PROMISC_PHYS); ++ PyModule_AddIntConstant(mod, "PROMISC_SAP", DL_PROMISC_SAP); ++ PyModule_AddIntConstant(mod, "PROMISC_MULTI", DL_PROMISC_MULTI); ++ //PyModule_AddIntConstant(mod, "PROMISC_NOLOOP", DL_PROMISC_NOLOOP); ++ PyModule_AddIntConstant(mod, "UNKNOWN", DL_UNKNOWN); ++ PyModule_AddIntConstant(mod, "UNBOUND", DL_UNBOUND); ++ PyModule_AddIntConstant(mod, "IDLE", DL_IDLE); ++ PyModule_AddIntConstant(mod, "SYSERR", DL_SYSERR); ++ ++ return mod; ++} diff --git a/build/python313/patches/module-priv-rbac.patch b/build/python313/patches/module-priv-rbac.patch new file mode 100644 index 0000000000..18048f7024 --- /dev/null +++ b/build/python313/patches/module-priv-rbac.patch @@ -0,0 +1,1291 @@ +This patch provides Python RBAC support. It may be contributed upstream at +some point, but the suitability (or lack thereof) has not yet been determined. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/Setup.local a/Modules/Setup.local +--- a~/Modules/Setup.local 1970-01-01 00:00:00 ++++ a/Modules/Setup.local 1970-01-01 00:00:00 +@@ -2,3 +2,5 @@ + + ucred ucred.c -ltsol + dlpi dlpimodule.c -ldlpi ++privileges privileges.c ++rbac pyrbac.c authattr.c execattr.c userattr.c -lnsl -lsocket -lsecdb +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/authattr.c a/Modules/authattr.c +--- a~/Modules/authattr.c 1970-01-01 00:00:00 ++++ a/Modules/authattr.c 1970-01-01 00:00:00 +@@ -0,0 +1,254 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * RBAC Bindings for Python - auth_attr functions ++ */ ++ ++#include ++#include "Python.h" ++#include "pyrbac.h" ++ ++static PyObject* ++pyrbac_setauthattr(PyObject* self, PyObject* args) { ++ setauthattr(); ++ return Py_None; ++} ++ ++static PyObject* ++pyrbac_endauthattr(PyObject* self, PyObject* args) { ++ endauthattr(); ++ return Py_None; ++} ++ ++PyObject* ++pyrbac_getauthnamattr(PyObject* self, char* authname, int mode) { ++ ++ ++ ++ authattr_t * ret_authattr = (mode == PYRBAC_NAM_MODE) ? getauthnam(authname) : getauthattr(); ++ if (ret_authattr == NULL) ++ return Py_None; ++ ++ PyObject* kv_data = PyDict_New(); ++ if (kv_data == NULL) { ++ free_authattr(ret_authattr); ++ return NULL; ++ } ++ ++ if(ret_authattr->attr != NULL) { ++ int len; ++ for(len = 0; len < ret_authattr->attr->length; len++) { ++ kv_t current = ret_authattr->attr->data[len]; ++ ++ PyObject* set = PyList_New(0); ++ char* saveptr; ++ char* item = strtok_r(current.value, ",", &saveptr); ++ PyList_Append(set, PyUnicode_FromString(item)); ++ ++ while((item = strtok_r(NULL, ",", &saveptr)) != NULL) { ++ if(PyList_Append(set, PyUnicode_FromString(item)) != 0) { ++ Py_XDECREF(set); ++ Py_XDECREF(kv_data); ++ free_authattr(ret_authattr); ++ return NULL; ++ } ++ } ++ if(PyDict_SetItemString(kv_data, current.key, set)) { ++ free_authattr(ret_authattr); ++ return NULL; ++ } ++ } ++ } ++ PyObject * retval = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:O}", ++ "name",ret_authattr->name, ++ "res1",ret_authattr->res1, ++ "res2",ret_authattr->res2, ++ "short",ret_authattr->short_desc, ++ "long",ret_authattr->long_desc, ++ "attributes",kv_data); ++ ++ free_authattr(ret_authattr); ++ return retval; ++ ++} ++ ++static PyObject* ++pyrbac_getauthattr(PyObject* self, PyObject* args) { ++ return(pyrbac_getauthnamattr(self, NULL, PYRBAC_ATTR_MODE)); ++} ++ ++static PyObject* ++pyrbac_getauthnam(PyObject* self, PyObject* args) { ++ char* name = NULL; ++ if(!PyArg_ParseTuple(args, "s:getauthnam", &name)) ++ return NULL; ++ return(pyrbac_getauthnamattr(self, name, PYRBAC_NAM_MODE)); ++} ++ ++static PyObject * ++pyrbac_chkauthattr(PyObject* self, PyObject* args) { ++ char* authstring = NULL; ++ char* username = NULL; ++ if(!PyArg_ParseTuple(args, "ss:chkauthattr", &authstring, &username)) ++ return NULL; ++ return PyBool_FromLong((long)chkauthattr(authstring, username)); ++} ++ ++static PyObject* ++pyrbac_authattr_next(PyObject* self) { ++ PyObject* retval = pyrbac_getauthattr(self, NULL); ++ if( retval == Py_None ) { ++ setauthattr(); ++ return NULL; ++ } ++ return retval; ++} ++static PyObject* ++pyrbac_authattr__iter__(PyObject* self) { ++ return self; ++} ++ ++typedef struct { ++ PyObject_HEAD ++} Authattr; ++ ++static void ++Authattr_dealloc(Authattr* self) { ++ endauthattr(); ++ Py_TYPE(self)->tp_free((PyObject*) self); ++} ++ ++static PyObject* ++Authattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { ++ Authattr *self; ++ self = (Authattr*)type->tp_alloc(type, 0); ++ ++ return ((PyObject *) self); ++} ++ ++static int ++Authattr_init(Authattr* self, PyObject *args, PyObject *kwargs) { ++ setauthattr(); ++ return 0; ++} ++ ++PyDoc_STRVAR(pyrbac_authattr__doc__, """provides interfaces to the auth_attr \ ++database. may be iterated over to return all auth_attr entries\n\n\ ++Methods provided:\n\ ++setauthattr\n\ ++endauthattr\n\ ++getauthattr\n\ ++chkauthattr\n\ ++getauthnam"""); ++ ++PyDoc_STRVAR(pyrbac_setauthattr__doc__, ++"\"rewinds\" the auth_attr functions to the first entry in the db. Called \ ++automatically by the constructor\n\tArguments: None\n\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_endauthattr__doc__, ++"closes the auth_attr database, cleans up storage. called automatically by \ ++the destructor\n\tArguments: None\n\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_chkauthattr__doc__, "verifies if a user has a given \ ++authorization.\n\tArguments: 2 Python strings, 'authname' and 'username'\n\ ++\tReturns: True if the user is authorized, False otherwise"); ++ ++PyDoc_STRVAR(pyrbac_getauthattr__doc__, ++"return one entry from the auth_attr database\n\ ++\tArguments: None\n\ ++\tReturns: a dict representing the authattr_t struct:\n\ ++\t\t\"name\": Authorization Name\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"short\": Short Description\n\ ++\t\t\"long\": Long Description\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value"); ++ ++PyDoc_STRVAR(pyrbac_getauthnam__doc__, ++"searches the auth_attr database for a given authorization name\n\ ++\tArguments: a Python string containing the auth name\n\ ++\tReturns: a dict representing the authattr_t struct:\n\ ++\t\t\"name\": Authorization Name\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"short\": Short Description\n\ ++\t\t\"long\": Long Description\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value"); ++ ++static PyMethodDef Authattr_methods[] = { ++ {"setauthattr", pyrbac_setauthattr, METH_NOARGS, pyrbac_setauthattr__doc__}, ++ {"endauthattr", pyrbac_endauthattr, METH_NOARGS, pyrbac_endauthattr__doc__}, ++ {"chkauthattr", pyrbac_chkauthattr, METH_VARARGS, pyrbac_chkauthattr__doc__}, ++ {"getauthattr", pyrbac_getauthattr, METH_NOARGS, pyrbac_getauthattr__doc__}, ++ {"getauthnam", pyrbac_getauthnam, METH_VARARGS, pyrbac_getauthnam__doc__}, ++ {NULL, NULL} ++}; ++ ++PyTypeObject AuthattrType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "rbac.authattr", /*tp_name*/ ++ sizeof(Authattr), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ (destructor)Authattr_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_reserved*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | ++ Py_TPFLAGS_BASETYPE, /*tp_flags*/ ++ pyrbac_authattr__doc__, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ pyrbac_authattr__iter__, /* tp_iter */ ++ pyrbac_authattr_next, /* tp_iternext */ ++ Authattr_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)Authattr_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ Authattr_new, /* tp_new */ ++ 0, /* tp_free */ ++ 0, /* tp_is_gc */ ++}; +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/execattr.c a/Modules/execattr.c +--- a~/Modules/execattr.c 1970-01-01 00:00:00 ++++ a/Modules/execattr.c 1970-01-01 00:00:00 +@@ -0,0 +1,305 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * RBAC Bindings for Python - exec_attr functions ++ */ ++ ++#include ++#include "Python.h" ++#include "pyrbac.h" ++ ++static PyObject * ++pyrbac_setexecattr(PyObject* self, PyObject* args) { ++ setexecattr(); ++ return Py_None; ++} ++ ++static PyObject * ++pyrbac_endexecattr(PyObject* self, PyObject* args) { ++ endexecattr(); ++ return Py_None; ++} ++ ++PyObject * ++pyrbac_getexecuserprofattr(PyObject* self, char* userprofname, char* type, char* id, int mode) { ++ ++ PyObject* ep_data = (mode == PYRBAC_ATTR_MODE) ? NULL : PyList_New(0); ++ ++ if (ep_data == NULL && mode != PYRBAC_ATTR_MODE ) ++ return NULL; ++ ++ execattr_t *execprof; ++ if (mode == PYRBAC_USER_MODE) ++ execprof = getexecuser(userprofname, type, id, GET_ALL); ++ else if (mode == PYRBAC_PROF_MODE) ++ execprof = getexecprof(userprofname, type, id, GET_ALL); ++ else if (mode == PYRBAC_ATTR_MODE) ++ execprof = getexecattr(); ++ else ++ return NULL; ++ ++ if (execprof == NULL) ++ return Py_None; ++ ++ execattr_t *execprof_head = execprof; ++ ++ while(execprof != NULL) { ++ ++ PyObject* kv_data = PyDict_New(); ++ ++ if(execprof->attr != NULL) { ++ int len; ++ for(len = 0; len < execprof->attr->length; len++) { ++ kv_t current = execprof->attr->data[len]; ++ ++ PyObject* set = PyList_New(0); ++ char* saveptr; ++ char* item = strtok_r(current.value, ",", &saveptr); ++ PyList_Append(set, PyUnicode_FromString(item)); ++ ++ while((item = strtok_r(NULL, ",", &saveptr)) != NULL) { ++ if(PyList_Append(set, PyUnicode_FromString(item)) != 0) { ++ Py_XDECREF(set); ++ Py_XDECREF(kv_data); ++ free_execattr(execprof_head); ++ return NULL; ++ } ++ } ++ if(PyDict_SetItemString(kv_data, current.key, set)) { ++ free_execattr(execprof_head); ++ return NULL; ++ } ++ } ++ } ++ PyObject* entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:s,s:O}", ++ "name", execprof->name, ++ "type", execprof->type, ++ "policy", execprof->policy, ++ "res1", execprof->res1, ++ "res2", execprof->res2, ++ "id", execprof->id, ++ "attributes", kv_data); ++ ++ if (entry == NULL) { ++ Py_XDECREF(kv_data); ++ free_execattr(execprof_head); ++ return NULL; ++ } ++ ++ if (mode == PYRBAC_ATTR_MODE) { ++ free_execattr(execprof_head); ++ return(entry); ++ } ++ PyList_Append(ep_data, entry); ++ execprof = execprof->next; ++ } ++ ++ free_execattr(execprof_head); ++ return(ep_data); ++ ++} ++ ++static PyObject * ++pyrbac_getexecuser(PyObject* self, PyObject* args) { ++ char* username = NULL; ++ char* type = NULL; ++ char* id = NULL; ++ ++ if(!PyArg_ParseTuple(args, "sss:getexecuser", &username, &type, &id)) ++ return NULL; ++ ++ return (pyrbac_getexecuserprofattr(self, username, type, id, PYRBAC_USER_MODE)); ++} ++ ++static PyObject * ++pyrbac_getexecprof(PyObject* self, PyObject* args) { ++ ++ char* profname = NULL; ++ char* type = NULL; ++ char* id = NULL; ++ ++ if(!PyArg_ParseTuple(args, "sss:getexecprof", &profname, &type, &id)) ++ return NULL; ++ ++ return (pyrbac_getexecuserprofattr(self, profname, type, id, PYRBAC_PROF_MODE)); ++} ++ ++static PyObject* ++pyrbac_getexecattr(PyObject* self, PyObject* args) { ++ return pyrbac_getexecuserprofattr(self, NULL, NULL, NULL, PYRBAC_ATTR_MODE); ++} ++ ++static PyObject* ++pyrbac_execattr_next(PyObject* self) { ++ PyObject* retval = pyrbac_getexecattr(self, NULL); ++ if( retval == Py_None ) { ++ setexecattr(); ++ return NULL; ++ } ++ return retval; ++} ++static PyObject* ++pyrbac_execattr__iter__(PyObject* self) { ++ return self; ++} ++ ++typedef struct { ++ PyObject_HEAD ++} Execattr; ++ ++static void ++Execattr_dealloc(Execattr* self) { ++ endexecattr(); ++ Py_TYPE(self)->tp_free((PyObject*) self); ++} ++ ++static PyObject* ++Execattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { ++ Execattr *self; ++ self = (Execattr*)type->tp_alloc(type, 0); ++ ++ return ((PyObject *) self); ++} ++ ++static int ++Execattr_init(Execattr* self, PyObject *args, PyObject *kwargs) { ++ setexecattr(); ++ return 0; ++} ++ ++PyDoc_STRVAR(pyrbac_execattr__doc__, "provides functions for \ ++interacting with the execution profiles database. May be iterated over to \ ++enumerate exec_attr(5) entries\n\n\ ++Methods provided:\n\ ++setexecattr\n\ ++endexecattr\n\ ++getexecattr\n\ ++getexecprof\n\ ++getexecuser"); ++ ++ ++PyDoc_STRVAR(pyrbac_setexecattr__doc__, ++"\"rewinds\" the exec_attr functions to the first entry in the db. Called \ ++automatically by the constructor.\n\ ++\tArguments: None\ ++\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_endexecattr__doc__, ++"closes the exec_attr database, cleans up storage. called automatically by \ ++the destructor.\n\ ++\tArguments: None\ ++\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_getexecuser__doc__, "corresponds with getexecuser(3SECDB)\ ++\nTakes: \'username\', \'type\', \'id\'\n\ ++Return: a single exec_attr entry\n\ ++\tArguments: None\n\ ++\tReturns: a dict representation of an execattr_t struct:\n\ ++\t\t\"name\": Authorization Name\n\ ++\t\t\"type\": Profile Type\n\ ++\t\t\"policy\": Policy attributes are relevant in\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"id\": unique identifier\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as\ ++either a list or a string depending on value"); ++ ++PyDoc_STRVAR(pyrbac_getexecprof__doc__, "corresponds with getexecprof(3SECDB)\ ++\nTakes: \'profile name\', \'type\', \'id\'\n\ ++\tReturns: a dict representation of an execattr_t struct:\n\ ++\t\t\"name\": Authorization Name\n\ ++\t\t\"type\": Profile Type\n\ ++\t\t\"policy\": Policy attributes are relevant in\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"id\": unique identifier\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as\ ++either a list or a string depending on value"); ++ ++PyDoc_STRVAR(pyrbac_getexecattr__doc__, "corresponds with getexecattr(3SECDB)\ ++\nTakes 0 arguments\n\ ++\tReturns: a dict representation of an execattr_t struct:\n\ ++\t\t\"name\": Authorization Name\n\ ++\t\t\"type\": Profile Type\n\ ++\t\t\"policy\": Policy attributes are relevant in\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"id\": unique identifier\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as\ ++either a list or a string depending on value"); ++ ++static PyMethodDef Execattr_methods[] = { ++ {"setexecattr", pyrbac_setexecattr, METH_NOARGS, pyrbac_setexecattr__doc__}, ++ {"endexecattr", pyrbac_endexecattr, METH_NOARGS, pyrbac_endexecattr__doc__}, ++ {"getexecprof", pyrbac_getexecprof, METH_VARARGS, pyrbac_getexecprof__doc__}, ++ {"getexecuser", pyrbac_getexecuser, METH_VARARGS, pyrbac_getexecuser__doc__}, ++ {"getexecattr", pyrbac_getexecattr, METH_NOARGS, pyrbac_getexecattr__doc__}, ++ {NULL, NULL} ++}; ++ ++PyTypeObject ExecattrType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "rbac.execattr", /*tp_name*/ ++ sizeof(Execattr), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ (destructor)Execattr_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_reserved*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | ++ Py_TPFLAGS_BASETYPE, /*tp_flags*/ ++ pyrbac_execattr__doc__, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ pyrbac_execattr__iter__, /* tp_iter */ ++ pyrbac_execattr_next, /* tp_iternext */ ++ Execattr_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)Execattr_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ Execattr_new, /* tp_new */ ++ 0, /* tp_free */ ++ 0, /* tp_is_gc */ ++}; +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/privileges.c a/Modules/privileges.c +--- a~/Modules/privileges.c 1970-01-01 00:00:00 ++++ a/Modules/privileges.c 1970-01-01 00:00:00 +@@ -0,0 +1,269 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. ++ */ ++ ++/* ++ * privileges(7) bindings for Python ++ */ ++ ++#include ++#include "Python.h" ++ ++/* ++ * In userspace, privilege types are represented as strings. ++ * In the python library, numbers are used. This is the translation table. ++ */ ++struct xlate { ++ int cmd; ++ priv_ptype_t op; ++ const char *name; ++} xlates[] = { ++ { 0, PRIV_EFFECTIVE, "PRIV_EFFECTIVE" }, ++ { 1, PRIV_INHERITABLE, "PRIV_INHERITABLE" }, ++ { 2, PRIV_PERMITTED, "PRIV_PERMITTED" }, ++ { 3, PRIV_LIMIT, "PRIV_LIMIT" }, ++ { 0, NULL, NULL } ++}; ++ ++static PyObject * ++pyprivileges_setppriv( PyObject *self, PyObject *args) { ++ priv_op_t op = -1 ; ++ priv_ptype_t which = NULL; ++ int cmd, i; ++ ++ PyObject* set_list = NULL; ++ ++ priv_set_t * set = NULL; ++ ++ if(!PyArg_ParseTuple(args, "iiO:setppriv", &op, &cmd, &set_list)) ++ return NULL; ++ ++ for (i = 0; xlates[i].op != NULL; i++) { ++ if (xlates[i].cmd == cmd) { ++ which = xlates[i].op; ++ break; ++ } ++ } ++ ++ if (op != PRIV_ON && op != PRIV_OFF && op != PRIV_SET) ++ return NULL; ++ if (which == NULL) ++ return NULL; ++ ++ PyObject *set_string = PyList_GetItem(set_list, 0); ++ for (i = 1; i < PyList_Size(set_list); ++i) { ++ PyUnicode_Concat(set_string, PyUnicode_FromString(",")); ++ PyUnicode_Concat(set_string, PyList_GetItem(set_list, i)); ++ } ++ ++ set = priv_str_to_set( ++ PyBytes_AsString(PyUnicode_AsUTF8String(set_string)), ",", NULL ); ++ ++ if (set == NULL) ++ return NULL; ++ ++ long ret = (long) setppriv(op, which, set); ++ priv_freeset(set); ++ // Python inverts true & false ++ if(ret) ++ Py_RETURN_FALSE; ++ ++ Py_RETURN_TRUE; ++} ++ ++static PyObject * ++pyprivileges_getppriv( PyObject *self, PyObject *args) { ++ ++ char* set_str = NULL; ++ priv_ptype_t which = NULL; ++ priv_set_t * set = priv_allocset(); ++ int i, cmd; ++ ++ if (set == NULL) ++ return NULL; ++ ++ if(!PyArg_ParseTuple(args, "i:getppriv", &cmd)) ++ return NULL; ++ ++ for (i = 0; xlates[i].op != NULL; i++) { ++ if (xlates[i].cmd == cmd) { ++ which = xlates[i].op; ++ break; ++ } ++ } ++ ++ if (which == NULL) ++ return NULL; ++ ++ if (getppriv(which, set) != 0) ++ return NULL; ++ ++ set_str = priv_set_to_str(set, ',', PRIV_STR_LIT); ++ priv_freeset(set); ++ ++ PyObject* set_list = PyList_New(0); ++ char* saveptr; ++ char* item = strtok_r(set_str, ",", &saveptr); ++ PyList_Append(set_list, PyUnicode_FromString(item)); ++ ++ while((item = strtok_r(NULL, ",", &saveptr)) != NULL) { ++ if(PyList_Append(set_list, PyUnicode_FromString(item)) != 0) { ++ Py_XDECREF(set_list); ++ return NULL; ++ } ++ } ++ ++ return(set_list); ++} ++ ++static PyObject * ++pyprivileges_priv_inverse( PyObject *self, PyObject *args ) { ++ ++ PyObject* set_list_in = NULL; ++ if(!PyArg_ParseTuple(args, "O:priv_inverse", &set_list_in)) ++ return NULL; ++ ++ PyObject* set_string = PyList_GetItem(set_list_in, 0); ++ int i; ++ for (i = 1; i < PyList_Size(set_list_in); ++i) { ++ PyBytes_Concat(&set_string, PyBytes_FromString(",")); ++ PyBytes_Concat(&set_string, PyList_GetItem(set_list_in, i)); ++ } ++ ++ priv_set_t * set = priv_str_to_set(PyBytes_AsString(set_string), ",", NULL); ++ if (set == NULL) ++ return NULL; ++ priv_inverse(set); ++ char * ret_str = priv_set_to_str(set, ',', PRIV_STR_LIT); ++ priv_freeset(set); ++ ++ PyObject* set_list_out = PyList_New(0); ++ char* saveptr; ++ char* item = strtok_r(ret_str, ",", &saveptr); ++ PyList_Append(set_list_out, PyBytes_FromString(item)); ++ ++ while((item = strtok_r(NULL, ",", &saveptr)) != NULL) { ++ if(PyList_Append(set_list_out, PyBytes_FromString(item)) != 0) { ++ Py_XDECREF(set_list_out); ++ return NULL; ++ } ++ } ++ ++ Py_XDECREF(set_list_in); ++ ++ return(set_list_out); ++} ++ ++/* priv_ineffect is a convienient wrapper to priv_get ++ * however priv_set is, in the context of python, not ++ * much of a convienience, so it's omitted ++ */ ++static PyObject * ++pyprivileges_priv_ineffect(PyObject* self, PyObject* args) { ++ char* privstring=NULL; ++ if (!PyArg_ParseTuple(args, "s:priv_ineffect", &privstring)) ++ return NULL; ++ return PyBool_FromLong(priv_ineffect(privstring)); ++} ++ ++PyDoc_STRVAR(pyprivileges__doc__, ++"Provides functions for interacting with the Solaris privileges(7) framework\n\ ++Functions provided:\n\ ++setppriv\n\ ++getppriv\n\ ++priv_ineffect\n\ ++priv_inverse"); ++ ++PyDoc_STRVAR(pyprivileges_setppriv__doc__, ++"Facilitates setting the permitted/inheritable/limit/effective privileges set\n\ ++\tArguments:\n\ ++\t\tone of (PRIV_ON|PRIV_OFF|PRIV_SET)\n\ ++\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\ ++\t\tset of privileges: a list of strings\n\ ++\tReturns: True on success, False on failure\ ++"); ++ ++PyDoc_STRVAR(pyprivileges_getppriv__doc__, ++"Return the process privilege set\n\ ++\tArguments:\n\ ++\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\ ++\tReturns: a Python list of strings"); ++ ++PyDoc_STRVAR(pyprivileges_priv_ineffect__doc__, ++"Checks for a privileges presence in the effective set\n\ ++\tArguments: a String\n\ ++\tReturns: True if the privilege is in effect, False otherwise"); ++ ++PyDoc_STRVAR(pyprivileges_priv_inverse__doc__, ++"The complement of the set of privileges\n\ ++\tArguments: a list of strings\n\tReturns: a list of strings"); ++ ++static PyMethodDef module_methods[] = { ++ {"setppriv", pyprivileges_setppriv, METH_VARARGS, pyprivileges_setppriv__doc__}, ++ {"getppriv", pyprivileges_getppriv, METH_VARARGS, pyprivileges_getppriv__doc__}, ++ {"priv_ineffect", pyprivileges_priv_ineffect, METH_VARARGS, pyprivileges_priv_ineffect__doc__}, ++ {"priv_inverse", pyprivileges_priv_inverse, METH_VARARGS, pyprivileges_priv_inverse__doc__}, ++ {NULL, NULL} ++}; ++ ++ ++#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ ++#define PyMODINIT_FUNC void ++#endif ++PyMODINIT_FUNC ++PyInit_privileges (void) { ++ PyObject* m; ++ ++ static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ "privileges", ++ pyprivileges__doc__, ++ -1, ++ module_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ }; ++ ++ m = PyModule_Create(&moduledef); ++ if ( m == NULL ) ++ return m; ++ ++ PyObject* d = PyModule_GetDict(m); ++ if (d == NULL) ++ return m; ++ ++ PyDict_SetItemString(d, "PRIV_ON", PyLong_FromLong((long)PRIV_ON)); ++ PyDict_SetItemString(d, "PRIV_OFF", PyLong_FromLong((long)PRIV_OFF)); ++ PyDict_SetItemString(d, "PRIV_SET", PyLong_FromLong((long)PRIV_SET)); ++ ++ for (int i = 0; xlates[i].op != NULL; i++) { ++ PyDict_SetItemString(d, xlates[i].name, ++ PyLong_FromLong((long)xlates[i].cmd)); ++ } ++ ++ return m; ++} +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/pyrbac.c a/Modules/pyrbac.c +--- a~/Modules/pyrbac.c 1970-01-01 00:00:00 ++++ a/Modules/pyrbac.c 1970-01-01 00:00:00 +@@ -0,0 +1,81 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * RBAC Bindings for Python ++ */ ++ ++#include ++#include "pyrbac.h" ++ ++static PyMethodDef module_methods[] = {NULL}; ++ ++PyDoc_STRVAR(pyrbac__doc__, "provides access to some objects \ ++for interaction with the Solaris Role-Based Access Control \ ++framework.\n\nDynamic objects:\n\ ++userattr -- for interacting with user_attr(5)\n\ ++authattr -- for interacting with auth_attr(5)\n\ ++execattr -- for interacting with exec_attr(5)\n"); ++ ++#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ ++#define PyMODINIT_FUNC void ++#endif ++PyMODINIT_FUNC ++PyInit_rbac (void) { ++ PyObject* m; ++ ++ if (PyType_Ready(&AuthattrType) < 0 || ++ PyType_Ready(&ExecattrType) < 0 || ++ PyType_Ready(&UserattrType) < 0 ) ++ return NULL; ++ ++ static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ "rbac", ++ pyrbac__doc__, ++ -1, ++ module_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ }; ++ ++ m = PyModule_Create(&moduledef); ++ if ( m == NULL ) ++ return NULL; ++ ++ Py_INCREF(&AuthattrType); ++ PyModule_AddObject(m, "authattr", (PyObject*)&AuthattrType); ++ ++ Py_INCREF(&ExecattrType); ++ PyModule_AddObject(m, "execattr", (PyObject*)&ExecattrType); ++ ++ Py_INCREF(&UserattrType); ++ PyModule_AddObject(m, "userattr", (PyObject*)&UserattrType); ++ ++ return m; ++ ++} +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/pyrbac.h a/Modules/pyrbac.h +--- a~/Modules/pyrbac.h 1970-01-01 00:00:00 ++++ a/Modules/pyrbac.h 1970-01-01 00:00:00 +@@ -0,0 +1,45 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * RBAC bindings for python ++ */ ++#ifndef PYRBAC_H ++#define PYRBAC_H ++ ++#include ++ ++ ++#define PYRBAC_USER_MODE 1 ++#define PYRBAC_PROF_MODE 2 ++#define PYRBAC_ATTR_MODE 3 ++#define PYRBAC_NAM_MODE 4 ++#define PYRBAC_UID_MODE 5 ++ ++extern PyTypeObject AuthattrType; ++extern PyTypeObject ExecattrType; ++extern PyTypeObject UserattrType; ++ ++#endif +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/userattr.c a/Modules/userattr.c +--- a~/Modules/userattr.c 1970-01-01 00:00:00 ++++ a/Modules/userattr.c 1970-01-01 00:00:00 +@@ -0,0 +1,301 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++ ++/* ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * RBAC Bindings for Python - user_attr functions ++ */ ++ ++#include ++#include ++#include "Python.h" ++#include "pyrbac.h" ++ ++static PyObject* ++pyrbac_setuserattr(PyObject* self, PyObject* args) { ++ setuserattr(); ++ return Py_None; ++} ++ ++static PyObject* ++pyrbac_enduserattr(PyObject* self, PyObject* args) { ++ enduserattr(); ++ return Py_None; ++} ++ ++PyObject* ++pyrbac_getuseruidnamattr(PyObject* self, void* arg, int mode, char* filename) { ++ ++ userattr_t *ret_userattr = NULL; ++ ++ if (mode == PYRBAC_ATTR_MODE) { ++ if (filename != NULL) { ++ FILE* file = fopen(filename, "r"); ++ if (file == NULL) ++ return NULL; ++ ret_userattr = fgetuserattr(file); ++ if (fclose(file)) ++ return NULL; ++ } ++ else ++ ret_userattr = getuserattr(); ++ } ++ else if (mode == PYRBAC_NAM_MODE) ++ ret_userattr = getusernam((char*) arg); ++ else if (mode == PYRBAC_UID_MODE) ++ ret_userattr = getuseruid(*((uid_t*) arg)); ++ ++ if (ret_userattr == NULL) ++ return Py_None; ++ ++ PyObject* entry = PyTuple_New(5); ++ if (entry == NULL) { ++ free_userattr(ret_userattr); ++ return NULL; ++ } ++ ++ PyObject* kv_data = PyDict_New(); ++ ++ if(ret_userattr->attr != NULL) { ++ int len; ++ for(len = 0; len < ret_userattr->attr->length; len++) { ++ kv_t current = ret_userattr->attr->data[len]; ++ ++ PyObject* set = PyList_New(0); ++ char* saveptr; ++ char* item = strtok_r(current.value, ",", &saveptr); ++ PyList_Append(set, PyBytes_FromString(item)); ++ ++ while((item = strtok_r(NULL, ",", &saveptr)) != NULL) { ++ if(PyList_Append(set, PyBytes_FromString(item)) != 0) { ++ Py_XDECREF(set); ++ Py_XDECREF(kv_data); ++ free_userattr(ret_userattr); ++ return NULL; ++ } ++ } ++ if(PyDict_SetItemString(kv_data, current.key, set)) { ++ free_userattr(ret_userattr); ++ return NULL; ++ } ++ } ++ } ++ entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:O}", ++ "name", ret_userattr->name, ++ "qualifier", ret_userattr->qualifier, ++ "res1", ret_userattr->res1, ++ "res2", ret_userattr->res2, ++ "attributes", kv_data); ++ ++ free_userattr(ret_userattr); ++ ++ return entry; ++} ++ ++ ++static PyObject* ++pyrbac_getuserattr(PyObject* self, PyObject* args) { ++ return(pyrbac_getuseruidnamattr(self, (void*) NULL, PYRBAC_ATTR_MODE, NULL)); ++} ++ ++static PyObject* ++pyrbac_fgetuserattr(PyObject* self, PyObject* args) { ++ char* filename = NULL; ++ if(!PyArg_ParseTuple(args, "s:fgetuserattr", &filename)) ++ return NULL; ++ return(pyrbac_getuseruidnamattr(self, NULL, PYRBAC_ATTR_MODE, filename)); ++} ++ ++static PyObject* ++pyrbac_getusernam(PyObject* self, PyObject* args) { ++ char* name = NULL; ++ if(!PyArg_ParseTuple(args, "s:getusernam", &name)) ++ return NULL; ++ return(pyrbac_getuseruidnamattr(self, (void*) name, PYRBAC_NAM_MODE, NULL)); ++} ++ ++static PyObject* ++pyrbac_getuseruid(PyObject* self, PyObject* args) { ++ uid_t uid; ++ if(!PyArg_ParseTuple(args, "i:getuseruid", &uid)) ++ return NULL; ++ return(pyrbac_getuseruidnamattr(self, (void*) &uid, PYRBAC_UID_MODE, NULL)); ++} ++ ++static PyObject* ++pyrbac_userattr_next(PyObject* self) { ++ PyObject* retval = pyrbac_getuserattr(self, NULL); ++ if( retval == Py_None ) { ++ setuserattr(); ++ return NULL; ++ } ++ return retval; ++} ++static PyObject* ++pyrbac_userattr__iter__(PyObject* self) { ++ return self; ++} ++ ++typedef struct { ++ PyObject_HEAD ++} Userattr; ++ ++static void ++Userattr_dealloc(Userattr* self) { ++ enduserattr(); ++ Py_TYPE(self)->tp_free((PyObject*) self); ++} ++ ++static PyObject* ++Userattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { ++ Userattr *self; ++ self = (Userattr*)type->tp_alloc(type, 0); ++ ++ return ((PyObject *) self); ++} ++ ++static int ++Userattr_init(Userattr* self, PyObject *args, PyObject *kwargs) { ++ setuserattr(); ++ return 0; ++} ++ ++PyDoc_STRVAR(pyrbac_userattr__doc__, "provides functions for \ ++interacting with the extended user attributes database. May be iterated over \ ++to enumerate user_attr(5) entries\n\n\ ++Methods provided:\n\ ++setuserattr\n\ ++enduserattr\n\ ++getuserattr\n\ ++fgetuserattr\n\ ++getusernam\n\ ++getuseruid"); ++ ++PyDoc_STRVAR(pyrbac_setuserattr__doc__, "\"rewinds\" the user_attr functions \ ++to the first entry in the db. Called automatically by the constructor.\n\ ++\tArguments: None\n\ ++\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_enduserattr__doc__, "closes the user_attr database, \ ++cleans up storage. called automatically by the destructor\n\ ++\tArguments: None\n\ ++\tReturns: None"); ++ ++PyDoc_STRVAR(pyrbac_getuserattr__doc__, "Return a single user_attr entry\n \ ++\tArguments: None\n\ ++\tReturns: a dict representation of a userattr_t struct:\n\ ++\t\t\"name\": username\n\ ++\t\t\"qualifier\": reserved\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value" ++); ++ ++PyDoc_STRVAR(pyrbac_fgetuserattr__doc__, "Return a single user_attr entry \ ++from a file, bypassing nsswitch.conf\n\ ++\tArguments: \'filename\'\n\ ++\tReturns: a dict representation of a userattr_t struct:\n\ ++\t\t\"name\": username\n\ ++\t\t\"qualifier\": reserved\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value"); ++ ++PyDoc_STRVAR(pyrbac_getusernam__doc__, "Searches for a user_attr entry with a \ ++given user name\n\ ++\tArgument: \'username\'\n\ ++\tReturns: a dict representation of a userattr_t struct:\n\ ++\t\t\"name\": username\n\ ++\t\t\"qualifier\": reserved\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value"); ++ ++PyDoc_STRVAR(pyrbac_getuseruid__doc__, "Searches for a user_attr entry with a \ ++given uid\n\ ++\tArgument: uid\n\ ++\tReturns: a dict representation of a userattr_t struct:\n\ ++\t\t\"name\": username\n\ ++\t\t\"qualifier\": reserved\n\ ++\t\t\"res1\": reserved\n\ ++\t\t\"res2\": reserved\n\ ++\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \ ++or a string depending on value"); ++ ++static PyMethodDef Userattr_methods[] = { ++ {"setuserattr", pyrbac_setuserattr, METH_NOARGS, pyrbac_setuserattr__doc__}, ++ {"enduserattr", pyrbac_enduserattr, METH_NOARGS, pyrbac_enduserattr__doc__}, ++ {"getuserattr", pyrbac_getuserattr, METH_NOARGS, pyrbac_getuserattr__doc__}, ++ {"fgetuserattr", pyrbac_fgetuserattr, METH_VARARGS, pyrbac_fgetuserattr__doc__}, ++ {"getusernam", pyrbac_getusernam, METH_VARARGS, pyrbac_getusernam__doc__}, ++ {"getuseruid", pyrbac_getuseruid, METH_VARARGS, pyrbac_getuseruid__doc__}, ++ {NULL, NULL} ++}; ++ ++PyTypeObject UserattrType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "rbac.userattr", /*tp_name*/ ++ sizeof(Userattr), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ (destructor)Userattr_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_reserved*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT | ++ Py_TPFLAGS_BASETYPE, /*tp_flags*/ ++ pyrbac_userattr__doc__, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ pyrbac_userattr__iter__, /* tp_iter */ ++ pyrbac_userattr_next, /* tp_iternext */ ++ Userattr_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)Userattr_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ Userattr_new, /* tp_new */ ++ 0, /* tp_free */ ++ 0, /* tp_is_gc */ ++}; diff --git a/build/python313/patches/module-ucred.patch b/build/python313/patches/module-ucred.patch new file mode 100644 index 0000000000..688fe10bf7 --- /dev/null +++ b/build/python313/patches/module-ucred.patch @@ -0,0 +1,468 @@ +This patch provides Python ucred support. It may be contributed upstream at +some point, but the suitability (or lack thereof) has not yet been determined. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/ucredtest.py a/Lib/test/ucredtest.py +--- a~/Lib/test/ucredtest.py 1970-01-01 00:00:00 ++++ a/Lib/test/ucredtest.py 1970-01-01 00:00:00 +@@ -0,0 +1,45 @@ ++#!/usr/bin/python3 ++ ++import ucred ++import os ++ ++uc = ucred.get(os.getpid()) ++ ++print("pid = %d" % uc.getpid()) ++print("euid = %d" % uc.geteuid()) ++print("ruid = %d" % uc.getruid()) ++print("suid = %d" % uc.getsuid()) ++print("egid = %d" % uc.getegid()) ++print("rgid = %d" % uc.getrgid()) ++print("sgid = %d" % uc.getsgid()) ++print("zoneid = %d" % uc.getzoneid()) ++print("projid = %d" % uc.getprojid()) ++print("groups = %s" % uc.getgroups()) ++print("label = %s" % uc.getlabel()) ++ ++print("getpflags(0x1) = %d" % uc.getpflags(0x1)) ++print("getpflags(0x2) = %d" % uc.getpflags(0x2)) ++print("has_priv(Effective, proc_fork) = %d" % uc.has_priv("Effective", "proc_fork")) ++print("has_priv(Permitted, proc_fork) = %d" % uc.has_priv("Permitted", "proc_fork")) ++print("has_priv(Inheritable, proc_fork) = %d" % uc.has_priv("Inheritable", "proc_fork")) ++print("has_priv(Limit, file_setid) = %d" % uc.has_priv("Limit", "file_setid")) ++print("has_priv(Effective, file_setid) = %d" % uc.has_priv("Effective", "file_setid")) ++try: ++ uc.has_priv("Effective", "proc_bork") ++except OSError as e: ++ print(e) ++try: ++ uc.has_priv("Defective", "proc_fork") ++except OSError as e: ++ print(e) ++try: ++ uc.has_priv("Defective", "proc_bork") ++except OSError as e: ++ print(e) ++ ++del uc ++uc = ucred.ucred() ++try: ++ uc.getpid() ++except OSError as e: ++ print(e) +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/Setup.local a/Modules/Setup.local +--- a~/Modules/Setup.local 1970-01-01 00:00:00 ++++ a/Modules/Setup.local 1970-01-01 00:00:00 +@@ -0,0 +1,3 @@ ++# Edit this file for local setup changes ++ ++ucred ucred.c -ltsol +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/ucred.c a/Modules/ucred.c +--- a~/Modules/ucred.c 1970-01-01 00:00:00 ++++ a/Modules/ucred.c 1970-01-01 00:00:00 +@@ -0,0 +1,405 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++typedef struct { ++ PyObject_HEAD ++ ucred_t *ucred; ++} pyucred_t; ++ ++#define pyucred_getlongid(name, type) \ ++ static PyObject * \ ++ pyucred_get##name(pyucred_t *uc) \ ++ { \ ++ long val; \ ++ \ ++ if (uc->ucred == NULL) { \ ++ errno = EINVAL; \ ++ PyErr_SetFromErrno(PyExc_OSError); \ ++ return (NULL); \ ++ } \ ++ \ ++ if ((val = ucred_get##name(uc->ucred)) == -1) { \ ++ PyErr_SetFromErrno(PyExc_OSError); \ ++ return (NULL); \ ++ } \ ++ \ ++ return (Py_BuildValue("l", (long)val)); \ ++ } ++ ++pyucred_getlongid(euid, uid_t) ++pyucred_getlongid(ruid, uid_t) ++pyucred_getlongid(suid, uid_t) ++pyucred_getlongid(egid, gid_t) ++pyucred_getlongid(rgid, gid_t) ++pyucred_getlongid(sgid, gid_t) ++pyucred_getlongid(pid, pid_t) ++pyucred_getlongid(projid, projid_t) ++pyucred_getlongid(zoneid, zoneid_t) ++ ++static PyObject * ++pyucred_getgroups(pyucred_t *uc) ++{ ++ const gid_t *groups; ++ PyObject *list; ++ int len; ++ int i; ++ ++ if (uc->ucred == NULL) { ++ errno = EINVAL; ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ if ((len = ucred_getgroups(uc->ucred, &groups)) == -1) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ if ((list = PyList_New(len)) == NULL) ++ return (NULL); ++ ++ for (i = 0; i < len; i++) { ++ PyObject *gid = Py_BuildValue("l", (long)groups[i]); ++ if (PyList_SetItem(list, i, gid) == -1) ++ return (NULL); ++ } ++ ++ return (list); ++} ++ ++static PyObject * ++pyucred_getlabel(pyucred_t *uc) ++{ ++ m_label_t *label; ++ PyObject *ret; ++ char *str; ++ ++ if (uc->ucred == NULL) { ++ errno = EINVAL; ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ label = ucred_getlabel(uc->ucred); ++ if (label == NULL) ++ return (Py_BuildValue("s", "")); ++ ++ if (label_to_str(label, &str, M_LABEL, DEF_NAMES) == -1) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ ret = Py_BuildValue("s", str); ++ free(str); ++ return (ret); ++} ++ ++static PyObject * ++pyucred_getpflags(pyucred_t *uc, PyObject *args, PyObject *kwargs) ++{ ++ static char *kwlist[] = { "flags", NULL }; ++ uint_t flags; ++ ++ if (uc->ucred == NULL) { ++ errno = EINVAL; ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, ++ &flags)) ++ return (NULL); ++ ++ if ((flags = ucred_getpflags(uc->ucred, flags)) == (uint_t)-1) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ return (Py_BuildValue("i", flags)); ++} ++ ++static PyObject * ++pyucred_has_priv(pyucred_t *uc, PyObject *args, PyObject *kwargs) ++{ ++ static char *kwlist[] = { "set", "priv", NULL }; ++ const priv_set_t *privs; ++ const char *set; ++ const char *priv; ++ ++ if (uc->ucred == NULL) { ++ errno = EINVAL; ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss", kwlist, ++ &set, &priv)) ++ return (NULL); ++ ++ if ((privs = ucred_getprivset(uc->ucred, set)) == NULL) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ if (priv_ismember(privs, priv)) { ++ Py_INCREF(Py_True); ++ return Py_True; ++ } ++ ++ Py_INCREF(Py_False); ++ return Py_False; ++} ++ ++PyDoc_STRVAR(pyucred_getlabel_doc, ++ "getlabel() -> string\n" ++ "\n" ++ "Return the Trusted Extensions label string, or an " ++ "empty string if not available. The label string is " ++ "converted using the default name and M_LABEL (human-readable). " ++ "Raises OSError. See label_to_str(3TSOL)."); ++PyDoc_STRVAR(pyucred_getpflags_doc, ++ "getpflags(flags) -> int\n" ++ "\n" ++ "Return the values of the specified privilege flags."); ++PyDoc_STRVAR(pyucred_has_priv_doc, ++ "has_priv(set, priv) -> bool\n" ++ "\n" ++ "Return true if the given privilege is set in the " ++ "specified set. Raises OSError if the set or privilege is " ++ "invalid, or a problem occurs.\n" ++ "\n" ++ "Currently, the following privilege sets are defined, as " ++ "described in privileges(7):\n" ++ "\n" ++ "Effective\n" ++ "Permitted\n" ++ "Inheritable\n" ++ "Limit\n"); ++ ++static PyMethodDef pyucred_methods[] = { ++ { "geteuid", (PyCFunction)(uintptr_t)pyucred_geteuid, METH_NOARGS, ++ "Return the effective user ID." }, ++ { "getruid", (PyCFunction)(uintptr_t)pyucred_getruid, METH_NOARGS, ++ "Return the real user ID." }, ++ { "getsuid", (PyCFunction)(uintptr_t)pyucred_getsuid, METH_NOARGS, ++ "Return the saved user ID." }, ++ { "getegid", (PyCFunction)(uintptr_t)pyucred_getegid, METH_NOARGS, ++ "Return the effective group ID." }, ++ { "getrgid", (PyCFunction)(uintptr_t)pyucred_getrgid, METH_NOARGS, ++ "Return the real group ID." }, ++ { "getsgid", (PyCFunction)(uintptr_t)pyucred_getsgid, METH_NOARGS, ++ "Return the saved group ID." }, ++ { "getpid", (PyCFunction)(uintptr_t)pyucred_getpid, METH_NOARGS, ++ "Return the effective user ID." }, ++ { "getprojid", (PyCFunction)(uintptr_t)pyucred_getprojid, METH_NOARGS, ++ "Return the project ID." }, ++ { "getzoneid", (PyCFunction)(uintptr_t)pyucred_getzoneid, METH_NOARGS, ++ "Return the zone ID." }, ++ { "getgroups", (PyCFunction)(uintptr_t)pyucred_getgroups, METH_NOARGS, ++ "Return a list of group IDs." }, ++ { "getlabel", (PyCFunction)(uintptr_t)pyucred_getlabel, METH_NOARGS, ++ pyucred_getlabel_doc }, ++ { "getpflags", (PyCFunction)(uintptr_t)pyucred_getpflags, ++ METH_VARARGS|METH_KEYWORDS, pyucred_getpflags_doc }, ++ { "has_priv", (PyCFunction)(uintptr_t)pyucred_has_priv, ++ METH_VARARGS|METH_KEYWORDS, pyucred_has_priv_doc }, ++ { NULL, NULL } ++}; ++ ++static int ++pyucred_init(PyObject *self, PyObject *args, PyObject *kwargs) ++{ ++ pyucred_t *uc = (pyucred_t *)self; ++ uc->ucred = NULL; ++ return (0); ++} ++ ++static void ++pyucred_dealloc(PyObject *self) ++{ ++ pyucred_t *uc = (pyucred_t *)self; ++ if (uc->ucred != NULL) ++ ucred_free(uc->ucred); ++ Py_TYPE(self)->tp_free(self); ++} ++ ++static PyTypeObject pyucred_type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "ucred.ucred", /*tp_name*/ ++ sizeof (pyucred_t), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ pyucred_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ 0, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_reserved*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash */ ++ 0, /*tp_call*/ ++ 0, /*tp_str*/ ++ 0, /*tp_getattro*/ ++ 0, /*tp_setattro*/ ++ 0, /*tp_as_buffer*/ ++ Py_TPFLAGS_DEFAULT, /*tp_flags*/ ++ "user credentials", /*tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ pyucred_methods, /* tp_methods */ ++ 0, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)pyucred_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ 0, /* tp_new */ ++ 0, /* tp_free */ ++ 0, /* tp_is_gc */ ++}; ++ ++static PyObject * ++pyucred_new(const ucred_t *uc) ++{ ++ pyucred_t *self; ++ ++ self = (pyucred_t *)PyObject_CallObject((PyObject *)&pyucred_type, NULL); ++ ++ if (self == NULL) ++ return (NULL); ++ ++ self->ucred = (ucred_t *)uc; ++ ++ return ((PyObject *)self); ++} ++ ++static PyObject * ++pyucred_get(PyObject *o, PyObject *args, PyObject *kwargs) ++{ ++ static char *kwlist[] = { "pid", NULL }; ++ ucred_t *ucred = NULL; ++ int pid; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, ++ &pid)) ++ return (NULL); ++ ++ ucred = ucred_get(pid); ++ ++ if (ucred == NULL) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ return (pyucred_new(ucred)); ++} ++ ++static PyObject * ++pyucred_getpeer(PyObject *o, PyObject *args, PyObject *kwargs) ++{ ++ static char *kwlist[] = { "fd", NULL }; ++ ucred_t *ucred = NULL; ++ int fd; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, ++ &fd)) ++ return (NULL); ++ ++ if (getpeerucred(fd, &ucred) == -1) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ return (NULL); ++ } ++ ++ return (pyucred_new(ucred)); ++} ++ ++PyDoc_STRVAR(pyucred_get_doc, ++ "get(pid) -> ucred\n" ++ "\n" ++ "Return the credentials of the specified process ID. " ++ "Raises OSError. See ucred_get(3C)."); ++PyDoc_STRVAR(pyucred_getpeer_doc, ++ "getpeer(fd) -> ucred\n" ++ "\n" ++ "Return the credentials of the peer endpoint of a " ++ "connection-oriented socket (SOCK_STREAM) or STREAM fd " ++ "at the time the endpoint was created or the connection " ++ "was established. Raises OSError. See getpeerucred(3C)."); ++ ++static struct PyMethodDef pyucred_module_methods[] = { ++ { "get", (PyCFunction)(uintptr_t)pyucred_get, ++ METH_VARARGS|METH_KEYWORDS, pyucred_get_doc }, ++ { "getpeer", (PyCFunction)(uintptr_t)pyucred_getpeer, ++ METH_VARARGS|METH_KEYWORDS, pyucred_getpeer_doc }, ++ { NULL, NULL, 0, NULL } ++}; ++ ++PyDoc_STRVAR(pyucred_module_doc, ++ "This module provides an interface to the user credential access " ++ "methods, obtainable either by process ID or file descriptor."); ++ ++PyMODINIT_FUNC ++PyInit_ucred (void) ++{ ++ PyObject *m; ++ ++ static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ "ucred", ++ pyucred_module_doc, ++ -1, ++ pyucred_module_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ }; ++ ++ m = PyModule_Create(&moduledef); ++ ++ pyucred_type.tp_new = PyType_GenericNew; ++ if (PyType_Ready(&pyucred_type) < 0) ++ return NULL; ++ ++ Py_INCREF(&pyucred_type); ++ ++ PyModule_AddObject(m, "ucred", (PyObject *)&pyucred_type); ++ ++ return m; ++} diff --git a/build/python313/patches/py_db.patch b/build/python313/patches/py_db.patch new file mode 100644 index 0000000000..da3953121a --- /dev/null +++ b/build/python313/patches/py_db.patch @@ -0,0 +1,775 @@ +This patch adds Python debugger support. It may be contributed upstream at +some point, but the suitability (or lack thereof) has not yet been determined. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Makefile.pre.in a/Makefile.pre.in +--- a~/Makefile.pre.in 1970-01-01 00:00:00 ++++ a/Makefile.pre.in 1970-01-01 00:00:00 +@@ -614,7 +614,7 @@ all: @DEF_MAKE_ALL_RULE@ + .PHONY: all + + .PHONY: build_all +-build_all: check-clean-src $(BUILDPYTHON) platform sharedmods \ ++build_all: check-clean-src $(BUILDPYTHON) platform sharedmods build-py_db \ + gdbhooks Programs/_testembed scripts checksharedmods rundsymutil + + .PHONY: build_wasm +@@ -828,6 +828,15 @@ libpython3.so: libpython$(LDVERSION).so + libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) + $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ + ++SHLIB_FLAGS = -shared -fpic ++ ++libpython$(LDVERSION)_db.so.1.0: $(srcdir)/py_db/libpython312_db.c ++ $(CC) -o $@ $(CFLAGS) $(PY_CFLAGS) $(PY_CPPFLAGS) $(CPPFLAGS) $(SHLIB_FLAGS) $< ++ ++build-py_db: libpython$(LDVERSION)_db.so.1.0 ++ ++install-py_db: libpython$(LDVERSION)_db.so.1.0 ++ $(INSTALL_SHARED) libpython$(LDVERSION)_db.so.1.0 $(DESTDIR)$(LIBDIR) + + libpython$(VERSION).sl: $(LIBRARY_OBJS) + $(LDSHARED) -o $@ $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) +@@ -1900,7 +1909,7 @@ multissltest: all + # which can lead to two parallel `./python setup.py build` processes that + # step on each others toes. + .PHONY: install +-install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@ ++install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall install-py_db @FRAMEWORKINSTALLLAST@ + if test "x$(ENSUREPIP)" != "xno" ; then \ + case $(ENSUREPIP) in \ + upgrade) ensurepip="--upgrade" ;; \ +diff -wpruN --no-dereference '--exclude=*.orig' a~/py_db/libpython312_db.c a/py_db/libpython312_db.c +--- a~/py_db/libpython312_db.c 1970-01-01 00:00:00 ++++ a/py_db/libpython312_db.c 1970-01-01 00:00:00 +@@ -0,0 +1,611 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++/* ++ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define Py_BUILD_CORE ++ ++#include ++#include ++#include "internal/pycore_runtime.h" ++#include "internal/pycore_interp.h" ++ ++#include "libpython312_db.h" ++ ++struct pydb_agent { ++ struct ps_prochandle *pdb_ph; ++ int pdb_vers; ++ int pdb_is_64bit; ++ int pdb_datamodel; ++}; ++ ++typedef uintptr_t (*pdi_next_cb_t)(pydb_iter_t *); ++ ++struct pydb_iter { ++ struct ps_prochandle *pdi_ph; ++ uintptr_t pdi_current; ++ pdi_next_cb_t pdi_nextf; ++}; ++ ++#define LIBPYTHON "libpython3.12.so" ++ ++#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ++ ++/* Generic interface to helper functions */ ++static ssize_t pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr, ++ unsigned char *buf, size_t buf_len); ++static int pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline, ++ int lastinst); ++static int pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm, ++ size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno); ++ ++/* datamodel specific implementation of helper functions */ ++static ssize_t pydb_strobj_readdata_native(pydb_agent_t *py, uintptr_t addr, ++ unsigned char *buf, size_t buf_len); ++static int pydb_frameinfo_native(pydb_agent_t *py, uintptr_t addr, char *funcnm, ++ size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno); ++ ++static ssize_t pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf, ++ size_t len); ++ ++/* Iterator function next routines. Plugable, configured by iterator init */ ++static uintptr_t pydb_frame_iter_next(pydb_iter_t *iter); ++static uintptr_t pydb_interp_iter_next(pydb_iter_t *iter); ++static uintptr_t pydb_thread_iter_next(pydb_iter_t *iter); ++ ++static const char *strbasename(const char *s); ++ ++static const char * ++strbasename(const char *s) ++{ ++ const char *p = strrchr(s, '/'); ++ ++ if (p == NULL) ++ return (s); ++ ++ return (++p); ++} ++ ++/* Agent creation / destruction routines */ ++ ++pydb_agent_t * ++pydb_agent_create(struct ps_prochandle *P, int vers) ++{ ++ pydb_agent_t *py; ++ int datamodel; ++ ++ if (vers != PYDB_VERSION) { ++ errno = ENOTSUP; ++ return (NULL); ++ } ++ ++ if (ps_pdmodel(P, &datamodel) != PS_OK) { ++ return (NULL); ++ } ++ ++ py = (pydb_agent_t *)malloc(sizeof (pydb_agent_t)); ++ if (py == NULL) { ++ return (NULL); ++ } ++ ++ py->pdb_ph = P; ++ py->pdb_vers = vers; ++ py->pdb_datamodel = datamodel; ++ py->pdb_is_64bit = 0; ++ ++ return (py); ++} ++ ++void ++pydb_agent_destroy(pydb_agent_t *py) ++{ ++ if (py == NULL) { ++ return; ++ } ++ ++ free(py); ++} ++ ++/* Helper functions */ ++static int ++pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline, ++ int lastinst) ++{ ++ unsigned char lnotab[4096]; ++ ssize_t lnotab_len; ++ int addr, line; ++ int i; ++ ++ lnotab_len = pydb_strobj_readdata(py, lnotab_addr, lnotab, ++ sizeof (lnotab)); ++ if (lnotab_len < 0) { ++ return (-1); ++ } ++ ++ /* ++ * Python's line number algorithm is arcane. See here for details: ++ * http://svn.python.org/projects/python/trunk/Objects/lnotab_notes.txt ++ */ ++ ++ line = firstline; ++ for (addr = i = 0; i < lnotab_len; i += 2) { ++ if (addr + lnotab[i] > lastinst) { ++ break; ++ } ++ addr += lnotab[i]; ++ line += lnotab[i + 1]; ++ } ++ ++ return (line); ++} ++ ++static ssize_t ++pydb_asciiobj_readdata(pydb_agent_t *py, uintptr_t addr, ++ unsigned char *buf, size_t buf_len) ++{ ++ PyASCIIObject sobj; ++ ssize_t obj_sz; ++ ssize_t read_sz; ++ psaddr_t asciiaddr; ++ ++ /* ++ * PyASCIIObjects are a type of Unicode string. They are identified ++ * as follows: ++ * - sobj.state.compact == 1 ++ * - sobj.state.ascii == 1 ++ * The length of the string is stored in sobj.length. The string ++ * itself follows the PyASCIIObject. ++ */ ++ ++ if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyASCIIObject)) ++ != PS_OK) { ++ return (-1); ++ } ++ ++ if (!sobj.state.compact || !sobj.state.ascii) { ++ return (-1); ++ } ++ ++ obj_sz = (ssize_t)sobj.length; ++ ++ read_sz = MIN(obj_sz, (ssize_t)buf_len); ++ asciiaddr = (psaddr_t)(addr + sizeof (PyASCIIObject)); ++ ++ if (ps_pread(py->pdb_ph, asciiaddr, buf, (size_t)read_sz) != PS_OK) { ++ return (-1); ++ } ++ ++ return (read_sz); ++} ++ ++static ssize_t ++pydb_asciiobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf, ++ size_t buf_len) ++{ ++ ssize_t read_sz; ++ ++ read_sz = pydb_asciiobj_readdata(py, addr, (unsigned char *)buf, ++ buf_len); ++ ++ if (read_sz >= 0) { ++ if (read_sz >= buf_len) { ++ read_sz = buf_len - 1; ++ } ++ ++ buf[read_sz] = '\0'; ++ } ++ ++ return (read_sz); ++} ++ ++static ssize_t ++pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr, ++ unsigned char *buf, size_t buf_len) ++{ ++ PyBytesObject sobj; ++ ssize_t obj_sz; ++ ssize_t read_sz; ++ psaddr_t straddr; ++ ++ /* ++ * PyBytesObject are variable size. The size of the PyBytesObject ++ * struct is fixed, and known at compile time; however, the size of the ++ * associated buffer is variable. The char[1] element at the end of the ++ * structure contains the string, and the ob_size of the PyBytesObject ++ * indicates how much extra space was allocated to contain the string ++ * buffer at the object's tail. Read in the fixed size portion of the ++ * object first, and then read the contents of the data buffer into the ++ * buffer passed by the caller. ++ */ ++ ++ if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyBytesObject)) ++ != PS_OK) { ++ return (-1); ++ } ++ ++ /* ++ * If we want to emulate PyBytes_GET_SIZE() instead of just calling ++ * Py_SIZE() directly, we need to do a ps_pread() of Py_TYPE(&sobj). ++ * PyBytes_Check() will try to access the type structure, but the ++ * address is not in the debugger's address space. ++ */ ++ obj_sz = (ssize_t)Py_SIZE(&sobj); ++ ++ read_sz = MIN(obj_sz, (ssize_t)buf_len); ++ straddr = (psaddr_t)(addr + offsetof(PyBytesObject, ob_sval)); ++ ++ if (ps_pread(py->pdb_ph, straddr, buf, (size_t)read_sz) != PS_OK) { ++ return (-1); ++ } ++ ++ return (read_sz); ++} ++ ++/* ++ * Most Python PyBytesObject contain strings, as one would expect. However, ++ * due to some sleazy hackery in parts of the Python code, some string objects ++ * are used as buffers for binary data. In the general case, ++ * pydb_strobj_readstr() should be used to read strings out of string objects. ++ * It wraps pydb_strobj_readdata(), which should be used by callers only when ++ * trying to retrieve binary data. (This routine does some string cleanup). ++ */ ++static ssize_t ++pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf, ++ size_t buf_len) ++{ ++ ssize_t read_sz; ++ ++ read_sz = pydb_strobj_readdata(py, addr, (unsigned char *)buf, buf_len); ++ ++ if (read_sz >= 0) { ++ if (read_sz >= buf_len) { ++ read_sz = buf_len - 1; ++ } ++ ++ buf[read_sz] = '\0'; ++ } ++ ++ return (read_sz); ++} ++ ++ ++static int ++pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm, ++ size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno) ++{ ++ PyFrameObject fo; ++ _PyInterpreterFrame ifo; ++ PyCodeObject co; ++ ssize_t rc; ++ int lasti; ++ ++ if (ps_pread(py->pdb_ph, addr, &fo, sizeof (PyFrameObject)) ++ != PS_OK) { ++ return (-1); ++ } ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)fo.f_frame, &ifo, sizeof (_PyInterpreterFrame)) ++ != PS_OK) { ++ return (-1); ++ } ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)ifo.f_code, &co, ++ sizeof (PyCodeObject)) != PS_OK) { ++ return (-1); ++ } ++ ++ rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_name, funcnm, ++ funcnm_sz); ++ if (rc < 0) { ++ return (-1); ++ } ++ ++ rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_filename, filenm, ++ filenm_sz); ++ if (rc < 0) { ++ return (-1); ++ } ++ ++ lasti = (int)(ifo.prev_instr - (_Py_CODEUNIT *)co.co_code_adaptive); ++ ++ *lineno = pydb_getlno(py, (uintptr_t)co.co_linetable, co.co_firstlineno, ++ lasti); ++ if (*lineno < 0) { ++ return (-1); ++ } ++ ++ return (0); ++} ++ ++/* Functions that are part of the library's interface */ ++ ++/* ++ * Given the address of a PyFrameObject, and a buffer of a known size, ++ * fill the buffer with a description of the frame. ++ */ ++int ++pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr, char *fbuf, ++ size_t bufsz, int verbose) ++{ ++ char funcname[1024]; ++ char filename[1024]; ++ char *fn; ++ int lineno; ++ int length = (py->pdb_is_64bit ? 16 : 8); ++ int rc; ++ ++ rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname), ++ filename, sizeof (filename), &lineno); ++ if (rc < 0) { ++ return (-1); ++ } ++ ++ if (!verbose) { ++ fn = (char *)strbasename(filename); ++ } else { ++ fn = filename; ++ } ++ ++ (void) snprintf(fbuf, bufsz, "%0.*lx %s:%d %s()\n", length, ++ frame_addr, fn, lineno, funcname); ++ ++ return (0); ++} ++ ++/* ++ * Return a description about a PyFrameObject, if the object is ++ * actually a PyFrameObject. In this case, the pc argument is checked ++ * to make sure that it came from a function that takes a PyFrameObject ++ * as its first (argv[0]) argument. ++ */ ++int ++pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc, uintptr_t frame_addr, ++ char *fbuf, size_t bufsz) ++{ ++ char funcname[1024]; ++ char filename[1024]; ++ int lineno; ++ int rc; ++ ps_sym_t psym; ++ ++ /* ++ * If PC doesn't match PyEval_EvalFrameEx in either libpython ++ * or the executable, don't decode it. ++ */ ++ if (ps_pglobal_sym(py->pdb_ph, LIBPYTHON, "PyEval_EvalFrameEx", &psym) ++ != PS_OK) { ++ return (-1); ++ } ++ ++ /* If symbol found, ensure that PC falls within PyEval_EvalFrameEx. */ ++ if (pc < psym.st_value || pc > psym.st_value + psym.st_size) { ++ return (-1); ++ } ++ ++ rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname), ++ filename, sizeof (filename), &lineno); ++ if (rc < 0) { ++ return (-1); ++ } ++ ++ (void) snprintf(fbuf, bufsz, "[ %s:%d (%s) ]\n", filename, lineno, ++ funcname); ++ ++ return (0); ++} ++ ++/* ++ * Walks the list of PyInterpreterState objects. If caller doesn't ++ * supply address of list, this method will look it up. ++ */ ++pydb_iter_t * ++pydb_interp_iter_init(pydb_agent_t *py, uintptr_t addr) ++{ ++ pydb_iter_t *itr; ++ _PyRuntimeState st; ++ uintptr_t i_addr; ++ int rc; ++ ++ if (addr == 0) { ++ rc = ps_pglobal_lookup(py->pdb_ph, LIBPYTHON, "_PyRuntime", ++ (psaddr_t *)&addr); ++ if (rc != PS_OK) { ++ return (NULL); ++ } ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)addr, &st, sizeof (_PyRuntimeState)) ++ != PS_OK) { ++ return (NULL); ++ } ++ ++ i_addr = (uintptr_t)st.interpreters.head; ++ ++ } else { ++ if (ps_pread(py->pdb_ph, (uintptr_t)addr, &i_addr, sizeof (uintptr_t)) ++ != PS_OK) { ++ return (NULL); ++ } ++ } ++ ++ itr = malloc(sizeof (pydb_iter_t)); ++ if (itr == NULL) { ++ return (NULL); ++ } ++ ++ itr->pdi_ph = py->pdb_ph; ++ itr->pdi_current = i_addr; ++ itr->pdi_nextf = pydb_interp_iter_next; ++ ++ return (itr); ++} ++ ++static uintptr_t ++pydb_interp_iter_next(pydb_iter_t *iter) ++{ ++ PyInterpreterState st; ++ uintptr_t cur; ++ ++ cur = iter->pdi_current; ++ ++ if (cur == 0) { ++ return (cur); ++ } ++ ++ if (ps_pread(iter->pdi_ph, cur, &st, sizeof (PyInterpreterState)) ++ != PS_OK) { ++ iter->pdi_current = 0; ++ return (0); ++ } ++ ++ iter->pdi_current = (uintptr_t)st.next; ++ ++ return (cur); ++} ++ ++/* ++ * Walk a list of Python PyFrameObjects. The addr argument must be ++ * the address of a valid PyThreadState object. ++ */ ++pydb_iter_t * ++pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr) ++{ ++ pydb_iter_t *itr; ++ PyThreadState ts; ++ _PyCFrame cf; ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)addr, &ts, sizeof (PyThreadState)) ++ != PS_OK) { ++ return (NULL); ++ } ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)ts.cframe, &cf, sizeof (_PyCFrame)) ++ != PS_OK) { ++ return (NULL); ++ } ++ ++ ++ itr = malloc(sizeof (pydb_iter_t)); ++ if (itr == NULL) { ++ return (NULL); ++ } ++ ++ itr->pdi_ph = py->pdb_ph; ++ itr->pdi_current = (uintptr_t)cf.current_frame; ++ itr->pdi_nextf = pydb_frame_iter_next; ++ ++ return (itr); ++} ++ ++static uintptr_t ++pydb_frame_iter_next(pydb_iter_t *iter) ++{ ++ PyFrameObject fo; ++ uintptr_t cur; ++ ++ cur = iter->pdi_current; ++ ++ if (cur == 0) { ++ return (cur); ++ } ++ ++ if (ps_pread(iter->pdi_ph, cur, &fo, sizeof (PyFrameObject)) ++ != PS_OK) { ++ iter->pdi_current = 0; ++ return (0); ++ } ++ ++ iter->pdi_current = (uintptr_t)fo.f_back; ++ ++ return (cur); ++} ++ ++/* ++ * Walk a list of Python PyThreadState objects. The addr argument must be ++ * the address of a valid PyInterpreterState object. ++ */ ++pydb_iter_t * ++pydb_thread_iter_init(pydb_agent_t *py, uintptr_t addr) ++{ ++ pydb_iter_t *itr; ++ PyInterpreterState is; ++ ++ if (ps_pread(py->pdb_ph, (uintptr_t)addr, &is, ++ sizeof (PyInterpreterState)) != PS_OK) { ++ return (NULL); ++ } ++ ++ itr = malloc(sizeof (pydb_iter_t)); ++ if (itr == NULL) { ++ return (NULL); ++ } ++ ++ itr->pdi_ph = py->pdb_ph; ++ itr->pdi_current = (uintptr_t)is.threads.head; ++ itr->pdi_nextf = pydb_thread_iter_next; ++ ++ return (itr); ++} ++ ++static uintptr_t ++pydb_thread_iter_next(pydb_iter_t *iter) ++{ ++ PyThreadState ts; ++ uintptr_t cur; ++ ++ cur = iter->pdi_current; ++ ++ if (cur == 0) { ++ return (cur); ++ } ++ ++ if (ps_pread(iter->pdi_ph, cur, &ts, sizeof (PyThreadState)) != PS_OK) { ++ iter->pdi_current = 0; ++ return (0); ++ } ++ ++ iter->pdi_current = (uintptr_t)ts.next; ++ ++ return (cur); ++} ++ ++ ++uintptr_t ++pydb_iter_next(pydb_iter_t *iter) ++{ ++ return (iter->pdi_nextf(iter)); ++} ++ ++void ++pydb_iter_fini(pydb_iter_t *iter) ++{ ++ if (iter == NULL) { ++ return; ++ } ++ ++ free(iter); ++} +diff -wpruN --no-dereference '--exclude=*.orig' a~/py_db/libpython312_db.h a/py_db/libpython312_db.h +--- a~/py_db/libpython312_db.h 1970-01-01 00:00:00 ++++ a/py_db/libpython312_db.h 1970-01-01 00:00:00 +@@ -0,0 +1,73 @@ ++/* ++ * CDDL HEADER START ++ * ++ * The contents of this file are subject to the terms of the ++ * Common Development and Distribution License (the "License"). ++ * You may not use this file except in compliance with the License. ++ * ++ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++ * or http://www.opensolaris.org/os/licensing. ++ * See the License for the specific language governing permissions ++ * and limitations under the License. ++ * ++ * When distributing Covered Code, include this CDDL HEADER in each ++ * file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++ * If applicable, add the following below this CDDL HEADER, with the ++ * fields enclosed by brackets "[]" replaced with your own identifying ++ * information: Portions Copyright [yyyy] [name of copyright owner] ++ * ++ * CDDL HEADER END ++ */ ++/* ++ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. ++ */ ++ ++#ifndef _LIBPYTHON312_DB_H ++#define _LIBPYTHON312_DB_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Agent is opaque to library's consumers. */ ++typedef struct pydb_agent pydb_agent_t; ++ ++/* ++ * Library's debug version is 1. Changes to interface should increase this ++ * number. ++ */ ++#define PYDB_VERSION 1 ++ ++/* Agent creation/destruction routines */ ++extern pydb_agent_t *pydb_agent_create(struct ps_prochandle *P, int vers); ++extern void pydb_agent_destroy(pydb_agent_t *py); ++ ++/* Used by callers that know they are looking at a PyFrameObject */ ++extern int pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr, ++ char *fbuf, size_t bufsz, int verbose); ++ ++/* ++ * Used by callers that don't know if they're looking at PyFrameObject. ++ * Checks PC for traceable functions. ++ */ ++extern int pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc, ++ uintptr_t frame_addr, char *fbuf, size_t bufsz); ++ ++/* Iterator functions */ ++typedef struct pydb_iter pydb_iter_t; ++ ++extern pydb_iter_t *pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr); ++extern pydb_iter_t *pydb_interp_iter_init(pydb_agent_t *py, ++ uintptr_t addr); ++extern pydb_iter_t *pydb_thread_iter_init(pydb_agent_t *py, ++ uintptr_t addr); ++extern void pydb_iter_fini(pydb_iter_t *iter); ++extern uintptr_t pydb_iter_next(pydb_iter_t *iter); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _LIBPYTHON312_DB_H */ +diff -wpruN --no-dereference '--exclude=*.orig' a~/py_db/mapfile-vers a/py_db/mapfile-vers +--- a~/py_db/mapfile-vers 1970-01-01 00:00:00 ++++ a/py_db/mapfile-vers 1970-01-01 00:00:00 +@@ -0,0 +1,39 @@ ++# ++# CDDL HEADER START ++# ++# The contents of this file are subject to the terms of the ++# Common Development and Distribution License (the "License"). ++# You may not use this file except in compliance with the License. ++# ++# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE ++# or http://www.opensolaris.org/os/licensing. ++# See the License for the specific language governing permissions ++# and limitations under the License. ++# ++# When distributing Covered Code, include this CDDL HEADER in each ++# file and include the License file at usr/src/OPENSOLARIS.LICENSE. ++# If applicable, add the following below this CDDL HEADER, with the ++# fields enclosed by brackets "[]" replaced with your own identifying ++# information: Portions Copyright [yyyy] [name of copyright owner] ++# ++# CDDL HEADER END ++# ++ ++# ++# Copyright (c) 2012, 2020, Oracle and/or its affiliates. ++# ++ ++SUNWprivate_1.1 { ++ global: ++ pydb_agent_create; ++ pydb_agent_destroy; ++ pydb_frame_iter_init; ++ pydb_get_frameinfo; ++ pydb_pc_frameinfo; ++ pydb_interp_iter_init; ++ pydb_thread_iter_init; ++ pydb_iter_fini; ++ pydb_iter_next; ++ local: ++ *; ++}; diff --git a/build/python313/patches/pyc-timestamp.patch b/build/python313/patches/pyc-timestamp.patch new file mode 100644 index 0000000000..6e2c39fdc5 --- /dev/null +++ b/build/python313/patches/pyc-timestamp.patch @@ -0,0 +1,26 @@ + +When packaging python modules along with their compiled source, we +deliberately set the timestamp attributes for both the source +and compiled file so that they are not recompiled the first time +root uses them (via pkg, for example). Doing so causes `pkg validate` +errors and slows down the initial invocation. + +However, the timestamp and size of the .py file is also embedded within +the .pyc header. This patch allows overriding that embedded timestamp +with a value of our choosing. See lib/functions.sh for how this is set. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/py_compile.py a/Lib/py_compile.py +--- a~/Lib/py_compile.py 1970-01-01 00:00:00 ++++ a/Lib/py_compile.py 1970-01-01 00:00:00 +@@ -159,6 +159,11 @@ def compile(file, cfile=None, dfile=None + pass + if invalidation_mode == PycInvalidationMode.TIMESTAMP: + source_stats = loader.path_stats(file) ++ if fpepoch := os.environ.get('FORCE_PYC_TIMESTAMP'): ++ try: ++ source_stats['mtime'] = int(fpepoch) ++ except ValueError: ++ raise ValueError("FORCE_PYC_TIMESTAMP is not a valid integer") + bytecode = importlib._bootstrap_external._code_to_timestamp_pyc( + code, source_stats['mtime'], source_stats['size']) + else: diff --git a/build/python313/patches/restore-dtrace.patch b/build/python313/patches/restore-dtrace.patch new file mode 100644 index 0000000000..d4a7bc28de --- /dev/null +++ b/build/python313/patches/restore-dtrace.patch @@ -0,0 +1,280 @@ +See https://github.com/python/cpython/issues/98894 + +Author: Bill Sommerfeld + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_dtrace.py a/Lib/test/test_dtrace.py +--- a~/Lib/test/test_dtrace.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_dtrace.py 1970-01-01 00:00:00 +@@ -126,7 +126,7 @@ class TraceTests: + def test_verify_call_opcodes(self): + """Ensure our call stack test hits all function call opcodes""" + +- opcodes = set(["CALL_FUNCTION", "CALL_FUNCTION_EX", "CALL_FUNCTION_KW"]) ++ opcodes = set(["CALL", "CALL_FUNCTION_EX"]) + + with open(abspath("call_stack.py")) as f: + code_string = f.read() +@@ -151,6 +151,7 @@ class TraceTests: + def test_gc(self): + self.run_case("gc") + ++ @unittest.skipIf(True, "not currently implemented") + def test_line(self): + self.run_case("line") + +@@ -183,6 +184,8 @@ class CheckDtraceProbes(unittest.TestCas + print(f"readelf version: {readelf_major_version}.{readelf_minor_version}") + else: + raise unittest.SkipTest("CPython must be configured with the --with-dtrace option.") ++ # These checks are only relevant with the SystemTap backend ++ SystemTapBackend().assert_usable() + + + @staticmethod +diff -wpruN --no-dereference '--exclude=*.orig' a~/Python/bytecodes.c a/Python/bytecodes.c +--- a~/Python/bytecodes.c 1970-01-01 00:00:00 ++++ a/Python/bytecodes.c 1970-01-01 00:00:00 +@@ -834,6 +834,7 @@ dummy_func( + SYNC_SP(); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(EMPTY()); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; +@@ -856,6 +857,7 @@ dummy_func( + STACK_SHRINK(1); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: +@@ -880,6 +882,7 @@ dummy_func( + Py_INCREF(retval); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: +@@ -1077,6 +1080,7 @@ dummy_func( + assert(oparg == 0 || oparg == 1); + gen->gi_frame_state = FRAME_SUSPENDED + oparg; + _PyFrame_SetStackPointer(frame, stack_pointer - 1); ++ DTRACE_FUNCTION_EXIT(); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_YIELD, + frame, this_instr, retval); +@@ -1108,6 +1112,7 @@ dummy_func( + gen->gi_frame_state = FRAME_SUSPENDED + oparg; + SYNC_SP(); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); +diff -wpruN --no-dereference '--exclude=*.orig' a~/Python/ceval.c a/Python/ceval.c +--- a~/Python/ceval.c 1970-01-01 00:00:00 ++++ a/Python/ceval.c 1970-01-01 00:00:00 +@@ -106,6 +106,70 @@ + } while (0) + #endif + ++static void ++dtrace_function_entry(_PyInterpreterFrame *frame) ++{ ++ const char *filename; ++ const char *funcname; ++ int lineno; ++ ++ PyCodeObject *code = _PyFrame_GetCode(frame); ++ filename = PyUnicode_AsUTF8(code->co_filename); ++ funcname = PyUnicode_AsUTF8(code->co_name); ++ lineno = PyUnstable_InterpreterFrame_GetLine(frame), ++ ++ PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); ++} ++ ++static void ++dtrace_function_return(_PyInterpreterFrame *frame) ++{ ++ const char *filename; ++ const char *funcname; ++ int lineno; ++ ++ PyCodeObject *code = _PyFrame_GetCode(frame); ++ filename = PyUnicode_AsUTF8(code->co_filename); ++ funcname = PyUnicode_AsUTF8(code->co_name); ++ lineno = PyUnstable_InterpreterFrame_GetLine(frame), ++ ++ PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); ++} ++ ++#if 0 ++/* DTrace equivalent of maybe_call_line_trace. */ ++static void ++maybe_dtrace_line(_PyInterpreterFrame *frame, ++ PyTraceInfo *trace_info, ++ int instr_prev) ++{ ++ const char *co_filename, *co_name; ++ ++ /* If the last instruction executed isn't in the current ++ instruction window, reset the window. ++ */ ++ initialize_trace_info(trace_info, frame); ++ int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &trace_info->bounds); ++ int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); ++ int line = _PyCode_CheckLineNumber(addr, &trace_info->bounds); ++ if (line != -1) { ++ /* Trace backward edges or first instruction of a new line */ ++ if (_PyInterpreterFrame_LASTI(frame) < instr_prev || ++ (line != lastline && addr == trace_info->bounds.ar_start)) ++ { ++ co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); ++ if (!co_filename) { ++ co_filename = "?"; ++ } ++ co_name = PyUnicode_AsUTF8(frame->f_code->co_name); ++ if (!co_name) { ++ co_name = "?"; ++ } ++ PyDTrace_LINE(co_filename, co_name, line); ++ } ++ } ++} ++#endif + + #ifdef LLTRACE + static void +@@ -732,6 +796,7 @@ _PyEval_EvalFrameDefault(PyThreadState * + if (_Py_EnterRecursivePy(tstate)) { + goto exit_unwind; + } ++ DTRACE_FUNCTION_ENTRY(); + /* Because this avoids the RESUME, + * we need to update instrumentation */ + _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); +@@ -757,6 +822,7 @@ start_frame: + } + + next_instr = frame->instr_ptr; ++ DTRACE_FUNCTION_ENTRY(); + resume_frame: + stack_pointer = _PyFrame_GetStackPointer(frame); + +@@ -893,6 +959,7 @@ exception_unwind: + } + assert(STACK_LEVEL() == 0); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + monitor_unwind(tstate, frame, next_instr-1); + goto exit_unwind; + } +diff -wpruN --no-dereference '--exclude=*.orig' a~/Python/ceval_macros.h a/Python/ceval_macros.h +--- a~/Python/ceval_macros.h 1970-01-01 00:00:00 ++++ a/Python/ceval_macros.h 1970-01-01 00:00:00 +@@ -297,6 +297,11 @@ GETITEM(PyObject *v, Py_ssize_t i) { + #define CONSTS() _PyFrame_GetCode(frame)->co_consts + #define NAMES() _PyFrame_GetCode(frame)->co_names + ++#define DTRACE_FUNCTION_EXIT() \ ++ if (PyDTrace_FUNCTION_RETURN_ENABLED()) { \ ++ dtrace_function_return(frame); \ ++ } ++ + #define DTRACE_FUNCTION_ENTRY() \ + if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ + dtrace_function_entry(frame); \ +diff -wpruN --no-dereference '--exclude=*.orig' a~/Python/generated_cases.c.h a/Python/generated_cases.c.h +--- a~/Python/generated_cases.c.h 1970-01-01 00:00:00 ++++ a/Python/generated_cases.c.h 1970-01-01 00:00:00 +@@ -996,6 +996,7 @@ + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; ++ DTRACE_FUNCTION_ENTRY(); + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); +@@ -1087,6 +1088,7 @@ + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; ++ DTRACE_FUNCTION_ENTRY(); + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); +@@ -1921,6 +1923,7 @@ + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; ++ DTRACE_FUNCTION_ENTRY(); + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); +@@ -1993,6 +1996,7 @@ + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; ++ DTRACE_FUNCTION_ENTRY(); + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); +@@ -2846,6 +2850,7 @@ + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; ++ DTRACE_FUNCTION_ENTRY(); + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); +@@ -3497,6 +3502,7 @@ + Py_INCREF(retval); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: +@@ -3522,6 +3528,7 @@ + STACK_SHRINK(1); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: +@@ -3547,6 +3554,7 @@ + assert(oparg == 0 || oparg == 1); + gen->gi_frame_state = FRAME_SUSPENDED + oparg; + _PyFrame_SetStackPointer(frame, stack_pointer - 1); ++ DTRACE_FUNCTION_EXIT(); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_YIELD, + frame, this_instr, retval); +@@ -5197,6 +5205,7 @@ + #endif + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(EMPTY()); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; +@@ -5254,6 +5263,7 @@ + stack_pointer += -1; + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(EMPTY()); ++ DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; +@@ -6230,6 +6240,7 @@ + gen->gi_frame_state = FRAME_SUSPENDED + oparg; + stack_pointer += -1; + _PyFrame_SetStackPointer(frame, stack_pointer); ++ DTRACE_FUNCTION_EXIT(); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); diff --git a/build/python313/patches/revert-makedirs.patch b/build/python313/patches/revert-makedirs.patch new file mode 100644 index 0000000000..73e741ef5b --- /dev/null +++ b/build/python313/patches/revert-makedirs.patch @@ -0,0 +1,46 @@ +This patch reverts changes made to `os.makedirs()` in Python 3.7. + +Prior to Python 3.7, mode argument also affected newly-created +intermediate-level directories, and that is not the case anymore [1]. The +reason was that with mode preventing directory creating, the function fails +after it creates the first intermediate-level directory. + +Since there is Solaris code that depends on the old behavior, this patch brings +it back. Note that we are not the only ones affected by this; upstream is +already considering reverting this change [2]. + +For reference: +[1] https://bugs.python.org/issue19930 +[2] https://bugs.python.org/issue42367 + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/os.py a/Lib/os.py +--- a~/Lib/os.py 1970-01-01 00:00:00 ++++ a/Lib/os.py 1970-01-01 00:00:00 +@@ -214,7 +214,7 @@ def makedirs(name, mode=0o777, exist_ok= + head, tail = path.split(head) + if head and tail and not path.exists(head): + try: +- makedirs(head, exist_ok=exist_ok) ++ makedirs(head, mode, exist_ok) + except FileExistsError: + # Defeats race condition when another thread created the path + pass +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_os.py a/Lib/test/test_os.py +--- a~/Lib/test/test_os.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_os.py 1970-01-01 00:00:00 +@@ -1764,12 +1764,12 @@ class MakedirTests(unittest.TestCase): + base = os_helper.TESTFN + parent = os.path.join(base, 'dir1') + path = os.path.join(parent, 'dir2') +- os.makedirs(path, 0o555) ++ os.makedirs(path, 0o755) + self.assertTrue(os.path.exists(path)) + self.assertTrue(os.path.isdir(path)) + if os.name != 'nt': +- self.assertEqual(os.stat(path).st_mode & 0o777, 0o555) +- self.assertEqual(os.stat(parent).st_mode & 0o777, 0o775) ++ self.assertEqual(os.stat(path).st_mode & 0o777, 0o755) ++ self.assertEqual(os.stat(parent).st_mode & 0o777, 0o755) + + @unittest.skipIf( + support.is_emscripten or support.is_wasi, diff --git a/build/python313/patches/series b/build/python313/patches/series new file mode 100644 index 0000000000..e67f8c4643 --- /dev/null +++ b/build/python313/patches/series @@ -0,0 +1,41 @@ +illumos.patch +autoconf-macros.patch +vendor-packages.patch +dont-use-ccs.patch +default-lib-path.patch +disable_epoll.patch +strxfrm-fix.patch +encoding-alias.patch +locale-encoding.patch +pyc-timestamp.patch +asyncio-watcher.patch +#XXX py_db.patch +restore-dtrace.patch +# +# Additional modules +module-ucred.patch +module-dlpi.patch +module-priv-rbac.patch +# +# Module fixes +mod-posix-sched_priority.patch +mod-shutil-sendfile.patch +termios-set-before-get.patch +# +# Test related +test-os.patch +test-email.patch +test-filecomments.patch +test-freeze.patch +test-metadata.patch +test-opts.patch +test-pkgutil.patch +test-processgroup.patch +test-tarfile.patch +test-zipfile.patch +test-re.patch +revert-makedirs.patch +# +# Do not add ustack.patch to this file, it is used to build the debug +# variant of python, see build.sh +gethostbyname.patch diff --git a/build/python313/patches/strxfrm-fix.patch b/build/python313/patches/strxfrm-fix.patch new file mode 100644 index 0000000000..83f15f2eca --- /dev/null +++ b/build/python313/patches/strxfrm-fix.patch @@ -0,0 +1,46 @@ +This patch fixes limitation in python which expects strxfrm function to return +string with characters with values lower than 10ffff. This is know issue: + +https://bugs.python.org/issue16258 + +This is not for upstream as the idea is from the bug itself and was rejected +for use on all platforms. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/_localemodule.c a/Modules/_localemodule.c +--- a~/Modules/_localemodule.c 1970-01-01 00:00:00 ++++ a/Modules/_localemodule.c 1970-01-01 00:00:00 +@@ -384,7 +384,7 @@ _locale_strxfrm_impl(PyObject *module, P + /*[clinic end generated code: output=3081866ebffc01af input=1378bbe6a88b4780]*/ + { + Py_ssize_t n1; +- wchar_t *s = NULL, *buf = NULL; ++ wchar_t *s = NULL, *buf = NULL, *solbuf = NULL; + size_t n2; + PyObject *result = NULL; + +@@ -425,8 +425,24 @@ _locale_strxfrm_impl(PyObject *module, P + goto exit; + } + } +- result = PyUnicode_FromWideChar(buf, n2); ++ ++ /* Split each character in resulting wide string in two ++ parts in order to prevent Python ValueErrors on Solaris. */ ++ solbuf = PyMem_New(wchar_t, (n2*2) + 1); ++ if (!solbuf) { ++ PyErr_NoMemory(); ++ goto exit; ++ } ++ unsigned int i, j; ++ for (i = 0, j = 0; i < n2; i ++, j+= 2) { ++ solbuf[j] = 0x10000 + (buf[i] >> 16); ++ solbuf[j+1] = buf[i] & 0xffff; ++ } ++ solbuf[j] = 0; ++ ++ result = PyUnicode_FromWideChar(solbuf, n2*2); + exit: ++ PyMem_Free(solbuf); + PyMem_Free(buf); + PyMem_Free(s); + return result; diff --git a/build/python313/patches/termios-set-before-get.patch b/build/python313/patches/termios-set-before-get.patch new file mode 100644 index 0000000000..500f8c0511 --- /dev/null +++ b/build/python313/patches/termios-set-before-get.patch @@ -0,0 +1,42 @@ +See https://github.com/python/cpython/issues/115189 + +Author: Bill Sommerfeld + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_termios.py a/Lib/test/test_termios.py +--- a~/Lib/test/test_termios.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_termios.py 1970-01-01 00:00:00 +@@ -13,6 +13,16 @@ class TestFunctions(unittest.TestCase): + + def setUp(self): + master_fd, self.fd = os.openpty() ++ # some systems will not let you get the window size unless it's been ++ # set first, so try to set it if we can't get it ++ try: ++ termios.tcgetwinsize(self.fd) ++ except termios.error: ++ try: ++ termios.tcsetwinsize(self.fd, (24, 80)) ++ except termios.error: ++ pass ++ + self.addCleanup(os.close, master_fd) + self.stream = self.enterContext(open(self.fd, 'wb', buffering=0)) + tmp = self.enterContext(tempfile.TemporaryFile(mode='wb', buffering=0)) +diff -wpruN --no-dereference '--exclude=*.orig' a~/Modules/termios.c a/Modules/termios.c +--- a~/Modules/termios.c 1970-01-01 00:00:00 ++++ a/Modules/termios.c 1970-01-01 00:00:00 +@@ -518,9 +518,12 @@ termios_tcsetwinsize_impl(PyObject *modu + #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) + struct winsize w; + /* Get the old winsize because it might have +- more fields such as xpixel, ypixel. */ ++ more fields such as xpixel, ypixel, but keep going and ++ try to set it even if this fails since on some systems ++ on a new pty you can't get the winsize until it's been ++ set once. */ + if (ioctl(fd, TIOCGWINSZ, &w) == -1) { +- return PyErr_SetFromErrno(state->TermiosError); ++ memset(&w, 0, sizeof(w)); + } + + w.ws_row = (unsigned short) winsz_0; diff --git a/build/python313/patches/test-email.patch b/build/python313/patches/test-email.patch new file mode 100644 index 0000000000..9287804908 --- /dev/null +++ b/build/python313/patches/test-email.patch @@ -0,0 +1,12 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_email/test_utils.py a/Lib/test/test_email/test_utils.py +--- a~/Lib/test/test_email/test_utils.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_email/test_utils.py 1970-01-01 00:00:00 +@@ -143,6 +143,8 @@ class LocaltimeTests(unittest.TestCase): + t2 = utils.localtime(t0.replace(tzinfo=None)) + self.assertEqual(t1, t2) + ++ @unittest.skipIf(sys.platform.startswith("sunos"), ++ "The Kyiv database on SunOS puts 1984 in EET") + @test.support.run_with_tz('Europe/Kyiv') + def test_variable_tzname(self): + t0 = datetime.datetime(1984, 1, 1, tzinfo=datetime.timezone.utc) diff --git a/build/python313/patches/test-filecomments.patch b/build/python313/patches/test-filecomments.patch new file mode 100644 index 0000000000..ab6828efd7 --- /dev/null +++ b/build/python313/patches/test-filecomments.patch @@ -0,0 +1,14 @@ + +Support comments in the test ignore file (see ../files/test.exclude) + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/libregrtest/cmdline.py a/Lib/test/libregrtest/cmdline.py +--- a~/Lib/test/libregrtest/cmdline.py 1970-01-01 00:00:00 ++++ a/Lib/test/libregrtest/cmdline.py 1970-01-01 00:00:00 +@@ -196,6 +196,7 @@ class FromFileFilterAction(argparse.Acti + items = getattr(namespace, self.dest) + with open(value, encoding='utf-8') as fp: + for line in fp: ++ if line.startswith('#'): continue + items.append((line.strip(), self.const)) + + diff --git a/build/python313/patches/test-freeze.patch b/build/python313/patches/test-freeze.patch new file mode 100644 index 0000000000..0105f1724f --- /dev/null +++ b/build/python313/patches/test-freeze.patch @@ -0,0 +1,36 @@ + +This patch: + + - updates the test to run GNU make; + - Strips all configure arguments of the form `--XXXdir=YYY` from the configure + lines used to build the new perl tree, since these override the temporary + --prefix being used for the test. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Tools/freeze/test/freeze.py a/Tools/freeze/test/freeze.py +--- a~/Tools/freeze/test/freeze.py 1970-01-01 00:00:00 ++++ a/Tools/freeze/test/freeze.py 1970-01-01 00:00:00 +@@ -6,6 +6,7 @@ import subprocess + import sysconfig + from test import support + ++import re + + def get_python_source_dir(): + src_dir = sysconfig.get_config_var('abs_srcdir') +@@ -18,7 +18,7 @@ TESTS_DIR = os.path.dirname(__file__) + TOOL_ROOT = os.path.dirname(TESTS_DIR) + SRCDIR = get_python_source_dir() + +-MAKE = shutil.which('make') ++MAKE = shutil.which('gmake') + FREEZE = os.path.join(TOOL_ROOT, 'freeze.py') + OUTDIR = os.path.join(TESTS_DIR, 'outdir') + +@@ -129,6 +129,7 @@ def prepare(script=None, outdir=None): + print(f'configuring python in {builddir}...') + config_args = shlex.split(sysconfig.get_config_var('CONFIG_ARGS') or '') + cmd = [os.path.join(srcdir, 'configure'), *config_args] ++ cmd = [c for c in cmd if not re.search(r'^--.*dir=', c)] + ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) + prefix = os.path.join(outdir, 'python-installation') + ensure_opt(cmd, 'prefix', prefix) diff --git a/build/python313/patches/test-metadata.patch b/build/python313/patches/test-metadata.patch new file mode 100644 index 0000000000..3cbc39970c --- /dev/null +++ b/build/python313/patches/test-metadata.patch @@ -0,0 +1,16 @@ + +The importlib test checks that there is no package called 'pkg', which is not +true on OmniOS. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_importlib/metadata/test_api.py a/Lib/test/test_importlib/metadata/test_api.py +--- a~/Lib/test/test_importlib/metadata/test_api.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_importlib/metadata/test_api.py 1970-01-01 00:00:00 +@@ -59,7 +59,7 @@ class APITests( + assert distribution(name).metadata['Name'] == 'pkg.dot' + + def test_prefix_not_matched(self): +- prefixes = 'p', 'pkg', 'pkg.' ++ prefixes = 'p', 'qkg', 'qkg.' + for prefix in prefixes: + with self.subTest(prefix): + with self.assertRaises(PackageNotFoundError): diff --git a/build/python313/patches/test-opts.patch b/build/python313/patches/test-opts.patch new file mode 100644 index 0000000000..36c7fb018c --- /dev/null +++ b/build/python313/patches/test-opts.patch @@ -0,0 +1,20 @@ + +When running the tests as part of the build, we want to run them in a +consistent order and not automatically re-launch them in verbose mode +when a failure occurs. + + -r Randomize test order + -w Re-run failed tests in verbose mode + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_regrtest.py a/Lib/test/test_regrtest.py +--- a~/Lib/test/test_regrtest.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_regrtest.py 1970-01-01 00:00:00 +@@ -804,7 +804,7 @@ class ProgramsTestCase(BaseTestCase): + self.tests = [self.create_test() for index in range(self.NTEST)] + + self.python_args = ['-Wd', '-E', '-bb'] +- self.regrtest_args = ['-uall', '-rwW', ++ self.regrtest_args = ['-uall', '-W', + '--testdir=%s' % self.tmptestdir] + self.regrtest_args.extend(('--timeout', '3600', '-j4')) + if sys.platform == 'win32': diff --git a/build/python313/patches/test-os.patch b/build/python313/patches/test-os.patch new file mode 100644 index 0000000000..91f37b957c --- /dev/null +++ b/build/python313/patches/test-os.patch @@ -0,0 +1,15 @@ + +Prior to being able to call `isatty()` or `ttyname()` on a new +subsidiary pty, the "ptem" module must be pushed there. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_os.py a/Lib/test/test_os.py +--- a~/Lib/test/test_os.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_os.py 1970-01-01 00:00:00 +@@ -4716,6 +4716,7 @@ class PseudoterminalTests(unittest.TestC + son_path = os.ptsname(mother_fd) + son_fd = os.open(son_path, os.O_RDWR|os.O_NOCTTY) + self.addCleanup(os.close, son_fd) ++ fcntl.ioctl(son_fd, fcntl.I_PUSH, "ptem") + self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd)) + + @unittest.skipUnless(hasattr(os, 'spawnl'), "need os.spawnl()") diff --git a/build/python313/patches/test-pkgutil.patch b/build/python313/patches/test-pkgutil.patch new file mode 100644 index 0000000000..1d796d7037 --- /dev/null +++ b/build/python313/patches/test-pkgutil.patch @@ -0,0 +1,43 @@ +Python does not expect the build system to already have a 'pkg' module, and +it may well have if it's an IPS image. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_pkgutil.py a/Lib/test/test_pkgutil.py +--- a~/Lib/test/test_pkgutil.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_pkgutil.py 1970-01-01 00:00:00 +@@ -582,22 +582,22 @@ class NestedNamespacePackageTest(unittes + pkgutil_boilerplate = ( + 'import pkgutil; ' + '__path__ = pkgutil.extend_path(__path__, __name__)') +- self.create_module('a.pkg.__init__', pkgutil_boilerplate) +- self.create_module('b.pkg.__init__', pkgutil_boilerplate) +- self.create_module('a.pkg.subpkg.__init__', pkgutil_boilerplate) +- self.create_module('b.pkg.subpkg.__init__', pkgutil_boilerplate) +- self.create_module('a.pkg.subpkg.c', 'c = 1') +- self.create_module('b.pkg.subpkg.d', 'd = 2') ++ self.create_module('a._pkg.__init__', pkgutil_boilerplate) ++ self.create_module('b._pkg.__init__', pkgutil_boilerplate) ++ self.create_module('a._pkg.subpkg.__init__', pkgutil_boilerplate) ++ self.create_module('b._pkg.subpkg.__init__', pkgutil_boilerplate) ++ self.create_module('a._pkg.subpkg.c', 'c = 1') ++ self.create_module('b._pkg.subpkg.d', 'd = 2') + sys.path.insert(0, os.path.join(self.basedir, 'a')) + sys.path.insert(0, os.path.join(self.basedir, 'b')) +- import pkg +- self.addCleanup(unload, 'pkg') +- self.assertEqual(len(pkg.__path__), 2) +- import pkg.subpkg +- self.addCleanup(unload, 'pkg.subpkg') +- self.assertEqual(len(pkg.subpkg.__path__), 2) +- from pkg.subpkg.c import c +- from pkg.subpkg.d import d ++ import _pkg ++ self.addCleanup(unload, '_pkg') ++ self.assertEqual(len(_pkg.__path__), 2) ++ import _pkg.subpkg ++ self.addCleanup(unload, '_pkg.subpkg') ++ self.assertEqual(len(_pkg.subpkg.__path__), 2) ++ from _pkg.subpkg.c import c ++ from _pkg.subpkg.d import d + self.assertEqual(c, 1) + self.assertEqual(d, 2) + diff --git a/build/python313/patches/test-processgroup.patch b/build/python313/patches/test-processgroup.patch new file mode 100644 index 0000000000..0994a45f7e --- /dev/null +++ b/build/python313/patches/test-processgroup.patch @@ -0,0 +1,18 @@ + +Running some sub-tests in process groups causes tests to hang - the reason it +not yet known. +Disable the use of process groups for now. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/libregrtest/worker.py a/Lib/test/libregrtest/worker.py +--- a~/Lib/test/libregrtest/worker.py 1970-01-01 00:00:00 ++++ a/Lib/test/libregrtest/worker.py 1970-01-01 00:00:00 +@@ -13,7 +13,8 @@ from .utils import ( + get_temp_dir, get_work_dir, exit_timeout) + + +-USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) ++USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg") ++ and not sys.platform.startswith("sunos")) + + + def create_worker_process(runtests: WorkerRunTests, output_fd: int, diff --git a/build/python313/patches/test-re.patch b/build/python313/patches/test-re.patch new file mode 100644 index 0000000000..dcd5aba97a --- /dev/null +++ b/build/python313/patches/test-re.patch @@ -0,0 +1,21 @@ +XXX TBD + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_re.py a/Lib/test/test_re.py +--- a~/Lib/test/test_re.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_re.py 1970-01-01 00:00:00 +@@ -2180,6 +2180,7 @@ class ReTests(unittest.TestCase): + is_emscripten or is_wasi, + "musl libc issue on Emscripten/WASI, bpo-46390" + ) ++ @unittest.skipIf(sys.platform.startswith("sunos"), "locale") + def test_locale_caching(self): + # Issue #22410 + oldlocale = locale.setlocale(locale.LC_CTYPE) +@@ -2220,6 +2221,7 @@ class ReTests(unittest.TestCase): + is_emscripten or is_wasi, + "musl libc issue on Emscripten/WASI, bpo-46390" + ) ++ @unittest.skipIf(sys.platform.startswith("sunos"), "locale") + def test_locale_compiled(self): + oldlocale = locale.setlocale(locale.LC_CTYPE) + self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale) diff --git a/build/python313/patches/test-tarfile.patch b/build/python313/patches/test-tarfile.patch new file mode 100644 index 0000000000..0413e1b095 --- /dev/null +++ b/build/python313/patches/test-tarfile.patch @@ -0,0 +1,20 @@ + +The resolution of file timestamps is different in ZFS to tmpfs, so the +comparison fails with an error like: + + AssertionError: 1686679063.0 not greater than or equal to 1686679063.8400018 + +Convert both timestamps to integer before comparing. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_tarfile.py a/Lib/test/test_tarfile.py +--- a~/Lib/test/test_tarfile.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_tarfile.py 1970-01-01 00:00:00 +@@ -3267,7 +3267,7 @@ class NoneInfoExtractTests(ReadTest): + if not path.is_symlink(): + raise + else: +- self.assertGreaterEqual(path.stat().st_mtime, now) ++ self.assertGreaterEqual(int(path.stat().st_mtime), int(now)) + + def test_extractall_none_mode(self): + # modes of directories and regular files should match the mode diff --git a/build/python313/patches/test-zipfile.patch b/build/python313/patches/test-zipfile.patch new file mode 100644 index 0000000000..828f558ebd --- /dev/null +++ b/build/python313/patches/test-zipfile.patch @@ -0,0 +1,18 @@ + +This test tries to set a file date to 2108-12-30. +On illumos, the os.utime() call raises: + OSError: [Errno 79] Value too large for defined data type +when the test expects an overflow error. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/test/test_zipfile/test_core.py a/Lib/test/test_zipfile/test_core.py +--- a~/Lib/test/test_zipfile/test_core.py 1970-01-01 00:00:00 ++++ a/Lib/test/test_zipfile/test_core.py 1970-01-01 00:00:00 +@@ -641,7 +641,7 @@ class StoredTestsWithSourceFile(Abstract + self.skipTest(f'time.localtime({ts}) raises OverflowError') + try: + os.utime(TESTFN, (ts, ts)) +- except OverflowError: ++ except (OverflowError, OSError): + self.skipTest('Host fs cannot set timestamp to required value.') + + mtime_ns = os.stat(TESTFN).st_mtime_ns diff --git a/build/python313/patches/ustack.patch b/build/python313/patches/ustack.patch new file mode 100644 index 0000000000..b1f177601b --- /dev/null +++ b/build/python313/patches/ustack.patch @@ -0,0 +1,668 @@ +From 91e13cc2104fc0dae396d59341ee8f23de2c3db5 Mon Sep 17 00:00:00 2001 +From: Andy Fiddaman +Date: Sat, 2 Mar 2024 17:38:00 +0000 +Subject: [PATCH] Python: Add dtrace ustack helper + +Python acquired native dtrace support in version 3.6, but without the +ustack helper that annotates stack traces with information about the +python function being called. + +This partially restores the ustack helper and is based on Sun's original dtrace +patches. + +Some more information on the original work can be found at: +https://movementarian.org/blog/posts/2007-05-24-python-and-dtrace-in-build-65 +--- + Include/dtrace.cpp.sh | 33 ++++ + Include/pydtrace.d | 149 ++++++++++++++++++ + Include/pydtrace.h | 12 +- + Include/pydtrace_offsets.c | 34 ++++ + Include/pydtrace_symbols.sh | 15 ++ + Lib/test/dtracedata/jstack.d | 18 +++ + Lib/test/dtracedata/jstack.d.expected | 21 +++ + Lib/test/dtracedata/jstack.py | 25 +++ + Lib/test/dtracedata/unicode-jstack.d | 18 +++ + Lib/test/dtracedata/unicode-jstack.d.expected | 18 +++ + Lib/test/dtracedata/unicode-jstack.py | 15 ++ + Lib/test/test_dtrace.py | 31 ++++ + Makefile.pre.in | 35 +++- + Python/ceval.c | 29 ++++ + Python/import.c | 4 +- + Python/sysmodule.c | 2 +- + 16 files changed, 447 insertions(+), 12 deletions(-) + create mode 100755 Include/dtrace.cpp.sh + create mode 100644 Include/pydtrace_offsets.c + create mode 100755 Include/pydtrace_symbols.sh + create mode 100644 Lib/test/dtracedata/jstack.d + create mode 100644 Lib/test/dtracedata/jstack.d.expected + create mode 100644 Lib/test/dtracedata/jstack.py + create mode 100644 Lib/test/dtracedata/unicode-jstack.d + create mode 100644 Lib/test/dtracedata/unicode-jstack.d.expected + create mode 100644 Lib/test/dtracedata/unicode-jstack.py + +diff --git a/Include/dtrace.cpp.sh b/Include/dtrace.cpp.sh +new file mode 100755 +index 0000000000..9a3fc3eed2 +--- /dev/null ++++ b/Include/dtrace.cpp.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++ ++# A cpp wrapper used by the dtrace compiler that strips //-style comments ++# and static inline functions ++ ++op=${@: -1} ++args=${@:1:$#-1} ++ ++# Our native cpp cannot cope with this, and we still need to remove some ++# pieces to keep the dtrace compiler happy. ++: "${DTRACE_CPP:=/opt/gcc-10/bin/cpp}" ++ ++$DTRACE_CPP $args \ ++ -D'__attribute__(x)=' \ ++ -D'__alignof__(x)=' \ ++ -D'__aligned(x)=' \ ++ -D__builtin_va_list='void *' \ ++ -D_Bool=char \ ++ -D_Noreturn= \ ++ -Dstring=_string \ ++ -Dcounter=_counter \ ++ | sed ' ++ s^//.*^^ ++ /^.*static inline .*/,/^}/d ++ /^.*static inline *$/,/^}/d ++ /\* *self\>/s/self/_&/ ++ /ob_refcnt_split/,/};/ { ++ s/};/} _u;/ ++ } ++ /__gnuc_va_list va_list\;/s/va_list;/_x_&/ ++ /^$/d ++' | tee dtrace.out >> $op ++ +diff --git a/Include/pydtrace.d b/Include/pydtrace.d +index 5e6a626b01..b45f5bb8c0 100644 +--- a/Include/pydtrace.d ++++ b/Include/pydtrace.d +@@ -20,3 +20,152 @@ provider python { + #pragma D attributes Evolving/Evolving/Common provider python function + #pragma D attributes Evolving/Evolving/Common provider python name + #pragma D attributes Evolving/Evolving/Common provider python args ++ ++#ifdef PYDTRACE_STACK_HELPER ++/* ++ * Python ustack helper. This relies on the first argument (PyFrame *) being ++ * on the stack; see Python/ceval.c for the contortions we go through to ensure ++ * this is the case. ++ * ++ * On x86, the PyFrame * is two slots up from the frame pointer. ++ * ++ * Some details about this in "Python and DTrace in build 65": ++ * https://movementarian.org/blog/posts/2007-05-24-python-and-dtrace-in-build-65 ++ */ ++ ++#include "pyconfig.h" ++#undef _POSIX_PTHREAD_SEMANTICS ++ ++#include ++#include ++ ++#define Py_EXPORTS_H ++#define Py_IMPORTED_SYMBOL ++#define Py_EXPORTED_SYMBOL ++#define Py_LOCAL_SYMBOL ++ ++#include "Python.h" ++#include "internal/pycore_frame.h" ++ ++#include "pydtrace_offsets.h" ++#include "pydtrace_symbols.h" ++ ++#define startframe _PyEval_EvalFrameDefaultReal ++#define endframe PYDTRACE_AFTER__PyEval_EvalFrameDefaultReal ++ ++extern uintptr_t startframe; ++extern uintptr_t endframe; ++ ++#define at_evalframe(addr) \ ++ ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \ ++ (uintptr_t)addr < ((uintptr_t)&``endframe)) ++ ++#define frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2) ++#define copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)(addr), sizeof(obj))) ++ ++/* ++ * Check if the string is ASCII. Don't use bitfields, because the ++ * packing in GCC and D are different. BEWARE!!!. ++ */ ++#define pystr_isascii(addr) \ ++ ((*(((char *)addr) + PYDTRACE_ASCII_OFFSET)) & PYDTRACE_ASCII_MASK) ++#define pystr_len(addr) \ ++ (pystr_isascii(addr) ? (addr)->_base.length : \ ++ *(Py_ssize_t *)(((char *)(addr)) + PYDTRACE_UTF8_LENGTH_OFFSET)) ++#define pystr_addr(addr, addr2) \ ++ (pystr_isascii(addr) ? \ ++ (char *)(((char *)(addr2)) + PYDTRACE_PyASCIIObject_SIZE) : \ ++ (char *)*(uintptr_t *)(((char *)(addr)) + PYDTRACE_UTF8_OFFSET)) ++ ++#define add_digit(nr, div) (((nr) / div) ? \ ++ (this->result[this->pos++] = '0' + (((nr) / div) % 10)) : \ ++ (this->result[this->pos] = '\0')) ++#define add_char(c) \ ++ (this->result[this->pos++] = c) ++#define add_hex(d) \ ++ add_char((d) < 10 ? '0' + (d) : 'a' - 10 + (d)) ++ ++#define add_number(i) \ ++ add_digit((i), 100000); \ ++ add_digit((i), 10000); \ ++ add_digit((i), 1000); \ ++ add_digit((i), 100); \ ++ add_digit((i), 10); \ ++ add_digit((i), 1) ++ ++#define add_pointer32(p) \ ++ add_hex((p >> 28) & 0xf); \ ++ add_hex((p >> 24) & 0xf); \ ++ add_hex((p >> 20) & 0xf); \ ++ add_hex((p >> 16) & 0xf); \ ++ add_hex((p >> 12) & 0xf); \ ++ add_hex((p >> 8) & 0xf); \ ++ add_hex((p >> 4) & 0xf); \ ++ add_hex((p) & 0xf) ++ ++#define add_pointer(p) \ ++ add_pointer32(p >> 32); \ ++ add_pointer32(p) ++ ++dtrace:helper:ustack: ++{ ++ this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t)); ++ this->frameo = copyin_obj(this->framep, struct _PyInterpreterFrame); ++ ++ /* ++ * Unfortunately for this ustack helper, python manages its own frames ++ * and in order to print them all we would have to walk the list at ++ * this->frameo->previous. We don't have a way of doing that yet - some ++ * inventive attempts have failed due to the lack of 'self' in this ++ * context - so we make do with printing the most recent stack frame. ++ */ ++ ++ this->codep = this->frameo->f_code; ++ this->codeo = copyin_obj(this->codep, PyCodeObject); ++ ++ this->filenameo = copyin_obj(this->codeo->co_filename, ++ PyCompactUnicodeObject); ++ this->nameo = copyin_obj(this->codeo->co_name, PyCompactUnicodeObject); ++ this->len_filename = pystr_len(this->filenameo); ++ this->len_name = pystr_len(this->nameo); ++ ++#if 0 ++ /* Line number determination still needs work */ ++ this->addr = this->frameo->prev_instr; ++ this->line = copyin_obj( ++ ((int32_t *)this->codeo->co_linetable)[(int32_t)this->addr], ++ int32_t); ++ this->lineno = *this->line; ++#else ++ this->lineno = 0; ++#endif ++ ++ this->len = 1 + this->len_filename + 1 + 5 + 2 + this->len_name + 1 + 1; ++ ++ this->result = (char *)alloca(this->len); ++ this->pos = 0; ++ add_char('@'); ++ ++ copyinto((uintptr_t)pystr_addr(this->filenameo, ++ this->codeo->co_filename), this->len_filename, ++ this->result + this->pos); ++ this->pos += this->len_filename; ++ ++ add_char(':'); ++ add_number(this->lineno); ++ add_char(' '); ++ add_char('('); ++ ++ copyinto((uintptr_t)pystr_addr(this->nameo, ++ this->codeo->co_name), this->len_name, ++ this->result + this->pos); ++ this->pos += this->len_name; ++ ++ add_char(')'); ++ this->result[this->pos] = '\0'; ++ ++ stringof(this->result) ++} ++ ++#endif /* PYDTRACE_STACK_HELPER */ ++ +diff --git a/Include/pydtrace.h b/Include/pydtrace.h +index e197d36694..35f01f7ddc 100644 +--- a/Include/pydtrace.h ++++ b/Include/pydtrace.h +@@ -25,18 +25,18 @@ extern "C" { + + /* Without DTrace, compile to nothing. */ + +-static inline void PyDTrace_LINE(const char *arg0, const char *arg1, int arg2) {} +-static inline void PyDTrace_FUNCTION_ENTRY(const char *arg0, const char *arg1, int arg2) {} +-static inline void PyDTrace_FUNCTION_RETURN(const char *arg0, const char *arg1, int arg2) {} ++static inline void PyDTrace_LINE(char *arg0, char *arg1, int arg2) {} ++static inline void PyDTrace_FUNCTION_ENTRY(char *arg0, char *arg1, int arg2) {} ++static inline void PyDTrace_FUNCTION_RETURN(char *arg0, char *arg1, int arg2) {} + static inline void PyDTrace_GC_START(int arg0) {} + static inline void PyDTrace_GC_DONE(Py_ssize_t arg0) {} + static inline void PyDTrace_INSTANCE_NEW_START(int arg0) {} + static inline void PyDTrace_INSTANCE_NEW_DONE(int arg0) {} + static inline void PyDTrace_INSTANCE_DELETE_START(int arg0) {} + static inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {} +-static inline void PyDTrace_IMPORT_FIND_LOAD_START(const char *arg0) {} +-static inline void PyDTrace_IMPORT_FIND_LOAD_DONE(const char *arg0, int arg1) {} +-static inline void PyDTrace_AUDIT(const char *arg0, void *arg1) {} ++static inline void PyDTrace_IMPORT_FIND_LOAD_START(char *arg0) {} ++static inline void PyDTrace_IMPORT_FIND_LOAD_DONE(char *arg0, int arg1) {} ++static inline void PyDTrace_AUDIT(char *arg0, void *arg1) {} + + static inline int PyDTrace_LINE_ENABLED(void) { return 0; } + static inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; } +diff --git a/Include/pydtrace_offsets.c b/Include/pydtrace_offsets.c +new file mode 100644 +index 0000000000..8cad556c84 +--- /dev/null ++++ b/Include/pydtrace_offsets.c +@@ -0,0 +1,34 @@ ++#include "Python.h" ++#include "unicodeobject.h" ++#include ++#include ++ ++int ++main(int argc, const char **argv) ++{ ++ PyCompactUnicodeObject o; ++ unsigned char *p = (unsigned char *)(&o); ++ ++ memset(&o, '\0', sizeof(o)); ++ o._base.state.ascii = 1; ++ while (*p == '\0') ++ p++; ++ ++ printf("/* File auto-generated. DO NOT MODIFY MANUALLY */\n"); ++ printf("\n"); ++ printf("#ifndef PYDTRACE_OFFSETS_H\n"); ++ printf("#define PYDTRACE_OFFSETS_H\n"); ++ printf("\n"); ++ printf("#define PYDTRACE_ASCII_OFFSET %ld\n", ++ p - (unsigned char *)(&o)); ++ printf("#define PYDTRACE_ASCII_MASK %d\n", *p); ++ printf("#define PYDTRACE_PyASCIIObject_SIZE %ld\n", ++ sizeof(PyASCIIObject)); ++ printf("#define PYDTRACE_UTF8_LENGTH_OFFSET %ld\n", ++ offsetof(PyCompactUnicodeObject, utf8_length)); ++ printf("#define PYDTRACE_UTF8_OFFSET %ld\n", ++ offsetof(PyCompactUnicodeObject, utf8)); ++ printf("\n"); ++ printf("#endif\n"); ++} ++ +diff --git a/Include/pydtrace_symbols.sh b/Include/pydtrace_symbols.sh +new file mode 100755 +index 0000000000..5672c2bb18 +--- /dev/null ++++ b/Include/pydtrace_symbols.sh +@@ -0,0 +1,15 @@ ++#!/bin/ksh ++ ++obj=${1:?obj} ++ ++# Find the function directly after the one that we want to annotate with ++# the dtrace ustack helper ++ ++func=_PyEval_EvalFrameDefaultReal ++sym=`/usr/bin/nm -hgp $obj \ ++ | grep ' T ' \ ++ | sort -n \ ++ | sed -n "/$func\$/{n;s/.* //;p;}"` ++ ++echo "#define PYDTRACE_AFTER_$func $sym" ++ +diff --git a/Lib/test/dtracedata/jstack.d b/Lib/test/dtracedata/jstack.d +new file mode 100644 +index 0000000000..46855b407c +--- /dev/null ++++ b/Lib/test/dtracedata/jstack.d +@@ -0,0 +1,18 @@ ++ ++python$target:::function-entry ++/copyinstr(arg1)=="test_stack"/ ++{ ++ self->trace = 1; ++} ++python$target:::function-entry ++/self->trace/ ++{ ++ printf("[x]"); ++ jstack(); ++} ++python$target:::function-return ++/copyinstr(arg1)=="test_stack"/ ++{ ++ self->trace = 0; ++} ++ +diff --git a/Lib/test/dtracedata/jstack.d.expected b/Lib/test/dtracedata/jstack.d.expected +new file mode 100644 +index 0000000000..9f1f389df7 +--- /dev/null ++++ b/Lib/test/dtracedata/jstack.d.expected +@@ -0,0 +1,21 @@ ++[x] ++[PyFile:17(test_stack)] ++[x] ++[PyFile:2(function_1)] ++[PyFile:17(test_stack)] ++[x] ++[PyFile:5(function_2)] ++[PyFile:17(test_stack)] ++[x] ++[PyFile:2(function_1)] ++[PyFile:5(function_2)] ++[PyFile:17(test_stack)] ++[x] ++[PyFile:8(function_3)] ++[PyFile:18(test_stack)] ++[x] ++[PyFile:11(function_4)] ++[PyFile:19(test_stack)] ++[x] ++[PyFile:14(function_5)] ++[PyFile:20(test_stack)] +\ No newline at end of file +diff --git a/Lib/test/dtracedata/jstack.py b/Lib/test/dtracedata/jstack.py +new file mode 100644 +index 0000000000..a1584ddf6f +--- /dev/null ++++ b/Lib/test/dtracedata/jstack.py +@@ -0,0 +1,25 @@ ++ ++def function_1(): ++ pass ++ ++def function_2(): ++ function_1() ++ ++def function_3(dummy, dummy2): ++ pass ++ ++def function_4(**dummy): ++ pass ++ ++def function_5(dummy, dummy2, **dummy3): ++ pass ++ ++def test_stack(): ++ function_1() ++ function_2() ++ function_3(*(1,2)) ++ function_4(**{"test":42}) ++ function_5(*(1,2), **{"test":42}) ++ ++test_stack() ++ +diff --git a/Lib/test/dtracedata/unicode-jstack.d b/Lib/test/dtracedata/unicode-jstack.d +new file mode 100644 +index 0000000000..c50a8d6785 +--- /dev/null ++++ b/Lib/test/dtracedata/unicode-jstack.d +@@ -0,0 +1,18 @@ ++ ++python$target:::function-entry ++/copyinstr(arg1)=="test_unicode_stack"/ ++{ ++ self->trace = 1; ++} ++python$target:::function-entry ++/self->trace/ ++{ ++ printf("[x]"); ++ jstack(); ++} ++python$target:::function-return ++/copyinstr(arg1)=="test_unicode_stack"/ ++{ ++ self->trace = 0; ++} ++ +diff --git a/Lib/test/dtracedata/unicode-jstack.d.expected b/Lib/test/dtracedata/unicode-jstack.d.expected +new file mode 100644 +index 0000000000..9e71506738 +--- /dev/null ++++ b/Lib/test/dtracedata/unicode-jstack.d.expected +@@ -0,0 +1,18 @@ ++[x] ++[PyFile:8(test_unicode_stack)] ++[x] ++[PyFile:2(function_1)] ++[PyFile:8(test_unicode_stack)] ++[x] ++[PyFile:9(únícódé)] ++[PyFile:9(test_unicode_stack)] ++[x] ++[PyFile:5(function_2)] ++[PyFile:9(únícódé)] ++[PyFile:9(test_unicode_stack)] ++[x] ++[PyFile:2(function_1)] ++[PyFile:5(function_2)] ++[PyFile:9(únícódé)] ++[PyFile:9(test_unicode_stack)] ++ +diff --git a/Lib/test/dtracedata/unicode-jstack.py b/Lib/test/dtracedata/unicode-jstack.py +new file mode 100644 +index 0000000000..d93e3d76b9 +--- /dev/null ++++ b/Lib/test/dtracedata/unicode-jstack.py +@@ -0,0 +1,15 @@ ++ ++def function_1(): ++ pass ++ ++def function_2(): ++ function_1() ++ ++def test_unicode_stack(): ++ def únícódé(): ++ function_2() ++ function_1() ++ únícódé() ++ ++test_unicode_stack() ++ +diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py +index 6f4c2313dd..fb8ba69209 100644 +--- a/Lib/test/test_dtrace.py ++++ b/Lib/test/test_dtrace.py +@@ -154,6 +154,37 @@ def test_gc(self): + def test_line(self): + self.run_case("line") + ++ def _jstack(self, name): ++ def _jstack_decode(str): ++ # When compiling with '--with-pydebug' ++ str = "".join(re.split(r'\[[0-9]+ refs\]', str)) ++ ++ str = [i for i in str.split("\n") \ ++ if (("[" in i) and not i.endswith(" () ]"))] ++ str = "\n".join(str) ++ str = str.replace("\r", "").replace(" ", "") ++ return str ++ ++ df = abspath(name + self.backend.EXTENSION) ++ pyf = abspath(name + ".py") ++ ++ output = self.backend.trace_python(script_file=df, python_file=pyf, ++ optimize_python=self.optimize_python) ++ ++ actual_result = _jstack_decode(output).replace(pyf, 'PyFile') ++ ++ with open(abspath(name + self.backend.EXTENSION + ".expected")) as f: ++ expected_result = f.read().rstrip() ++ ++ expected_result = expected_result.replace("\r", "").replace(" ", "") ++ ++ self.assertEqual(actual_result, expected_result) ++ ++ def test_jstack(self): ++ self._jstack("jstack") ++ ++ def test_unicode_jstack(self): ++ self._jstack("unicode-jstack") + + class DTraceNormalTests(TraceTests, unittest.TestCase): + backend = DTraceBackend() +diff --git a/Makefile.pre.in b/Makefile.pre.in +index dd5e69f7ab..81e738cf9d 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -1572,17 +1572,46 @@ Python/frozen.o: $(FROZEN_FILES_OUT) + # an include guard, so we can't use a pipeline to transform its output. + Include/pydtrace_probes.h: $(srcdir)/Include/pydtrace.d + $(MKDIR_P) Include +- $(DTRACE) $(DFLAGS) -o $@ -h -s $< ++ $(DTRACE) $(DFLAGS) -C -o $@ -h -s $< + : sed in-place edit with POSIX-only tools + sed 's/PYTHON_/PyDTrace_/' $@ > $@.tmp + mv $@.tmp $@ + ++Include/pydtrace_offsets: $(srcdir)/Include/pydtrace_offsets.c ++ $(MKDIR_P) Include ++ $(CC) $(PY_CORE_CFLAGS) -o $@ $< ++ ++Include/pydtrace_offsets.h: Include/pydtrace_offsets ++ $< > $@ ++ ++Include/pydtrace_symbols: $(srcdir)/Include/pydtrace_symbols.sh ++ $(MKDIR_P) Include ++ cp $< $@ ++ chmod +x $@ ++ ++Include/pydtrace_symbols.h: Include/pydtrace_symbols Python/ceval.o ++ $^ > $@ ++ ++Include/dtrace.cpp: $(srcdir)/Include/dtrace.cpp.sh ++ $(MKDIR_P) Include ++ cp $< $@ ++ chmod +x $@ ++ ++clean-dtrace: ++ rm -f Include/dtrace.cpp Include/pydtrace_symbols ++ rm -f Include/pydtrace_offsets Include/pydtrace_offsets.h ++ rm -f Include/pydtrace_symbols.h ++ + Python/ceval.o: $(srcdir)/Include/pydtrace.h + Python/import.o: $(srcdir)/Include/pydtrace.h + Modules/gcmodule.o: $(srcdir)/Include/pydtrace.h + ++Python/pydtrace.o: Include/dtrace.cpp ++Python/pydtrace.o: Include/pydtrace_offsets.h Include/pydtrace_symbols.h + Python/pydtrace.o: $(srcdir)/Include/pydtrace.d $(DTRACE_DEPS) +- $(DTRACE) $(DFLAGS) -o $@ -G -s $< $(DTRACE_DEPS) ++ $(DTRACE) $(DFLAGS) -DPYDTRACE_STACK_HELPER $(PY_CPPFLAGS) \ ++ -C -xcpppath=./Include/dtrace.cpp \ ++ -o $@ -G -s $< $(DTRACE_DEPS) + + Objects/typeobject.o: Objects/typeslots.inc + +@@ -2681,7 +2710,7 @@ profile-removal: + rm -f profile-bolt-stamp + + .PHONY: clean +-clean: clean-retain-profile clean-bolt ++clean: clean-retain-profile clean-bolt clean-dtrace + @if test @DEF_MAKE_ALL_RULE@ = profile-opt -o @DEF_MAKE_ALL_RULE@ = bolt-opt; then \ + rm -f profile-gen-stamp profile-clean-stamp; \ + $(MAKE) profile-removal; \ +diff --git a/Python/ceval.c b/Python/ceval.c +index b44ad31929..5fe0193f62 100644 +--- a/Python/ceval.c ++++ b/Python/ceval.c +@@ -657,7 +657,13 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { + #define PY_EVAL_C_STACK_UNITS 2 + + PyObject* _Py_HOT_FUNCTION ++#ifdef WITH_DTRACE ++_PyEval_EvalFrameDefaultReal( ++ long a1, long a2, long a3, long a4, PyThreadState *tstate, int throwflag, ++ _PyInterpreterFrame *frame) ++#else + _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) ++#endif + { + _Py_EnsureTstateNotNULL(tstate); + CALL_STAT_INC(pyeval_calls); +@@ -1028,6 +1034,29 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int + # pragma warning(pop) + #endif + ++#ifdef WITH_DTRACE ++ ++/* ++ * These shenanigans look like utter madness, but what we're actually doing is ++ * making sure that the ustack helper will see the PyFrameObject pointer on the ++ * stack. ++ * ++ * We use up the six registers for passing arguments, meaning the call can't ++ * use a register for passing 'f', and has to push it onto the stack in a known ++ * location. ++ */ ++ ++PyObject* __attribute__((noinline)) ++_PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *f, ++ int throwflag) ++{ ++ volatile PyObject *f2; ++ f2 = _PyEval_EvalFrameDefaultReal(0, 0, 0, 0, tstate, throwflag, f); ++ return (PyObject *)f2; ++} ++#endif ++ ++ + static void + format_missing(PyThreadState *tstate, const char *kind, + PyCodeObject *co, PyObject *names, PyObject *qualname) +diff --git a/Python/import.c b/Python/import.c +index db70909982..c3faef09f5 100644 +--- a/Python/import.c ++++ b/Python/import.c +@@ -2774,13 +2774,13 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) + } + + if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()) +- PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name)); ++ PyDTrace_IMPORT_FIND_LOAD_START((char *)PyUnicode_AsUTF8(abs_name)); + + mod = PyObject_CallMethodObjArgs(IMPORTLIB(interp), &_Py_ID(_find_and_load), + abs_name, IMPORT_FUNC(interp), NULL); + + if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED()) +- PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name), ++ PyDTrace_IMPORT_FIND_LOAD_DONE((char *)PyUnicode_AsUTF8(abs_name), + mod != NULL); + + if (import_time) { +diff --git a/Python/sysmodule.c b/Python/sysmodule.c +index 7874920a16..d0ff239743 100644 +--- a/Python/sysmodule.c ++++ b/Python/sysmodule.c +@@ -237,7 +237,7 @@ sys_audit_tstate(PyThreadState *ts, const char *event, + + /* Dtrace USDT point */ + if (dtrace) { +- PyDTrace_AUDIT(event, (void *)eventArgs); ++ PyDTrace_AUDIT((char *)event, (void *)eventArgs); + } + + /* Call interpreter hooks */ +-- +2.42.0 + diff --git a/build/python313/patches/vendor-packages.patch b/build/python313/patches/vendor-packages.patch new file mode 100644 index 0000000000..7e53bc4b45 --- /dev/null +++ b/build/python313/patches/vendor-packages.patch @@ -0,0 +1,8 @@ +This patch makes Python support the vendor-packages directory. +As it is OmniOS-specific, it is not suitable for upstream. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/Lib/site-packages/vendor-packages.pth a/Lib/site-packages/vendor-packages.pth +--- a~/Lib/site-packages/vendor-packages.pth 1970-01-01 00:00:00 ++++ a/Lib/site-packages/vendor-packages.pth 1970-01-01 00:00:00 +@@ -0,0 +1 @@ ++import site; site.addsitedir('/usr/lib/python3.12/vendor-packages') diff --git a/build/python313/pip/build.sh b/build/python313/pip/build.sh new file mode 100755 index 0000000000..fc249921a0 --- /dev/null +++ b/build/python313/pip/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/pip-313 +PROG=pip +inherit_ver python312/pip +SUMMARY="Tool for installing Python packages" +DESC="$PROG is the standard package installer for Python" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package $SRCDIR/../common.mog +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pip/local.mog b/build/python313/pip/local.mog new file mode 100644 index 0000000000..04c9369c03 --- /dev/null +++ b/build/python313/pip/local.mog @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.txt license=MIT + + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + + set pkg.depend.bypass-generate .* > + diff --git a/build/python313/pip/patches/protect-vendor-packages.patch b/build/python313/pip/patches/protect-vendor-packages.patch new file mode 100644 index 0000000000..268b23de0f --- /dev/null +++ b/build/python313/pip/patches/protect-vendor-packages.patch @@ -0,0 +1,87 @@ +This patch is partially based on one from + https://github.com/oracle/solaris-userland + +This is a workaround to reduce the risk of damage to IPS delivered Python +packages by `pip` operations. + +This patch prevents pip from uninstalling anything from the vendor-packages +folder. Pip can still see all packages in the vendor-packages folder (for +dependency resolution) but cannot remove them. This prevents pip from +uninstalling IPS related packages and thus breaking the system. + +Updating a system package via pip will now result in the new being installed +into the site-packages folder, and the old being left in place. This retains +the version that is needed for system tools like `pkg` because these tools +explicitly ignore the `site-packages` area. + +All to-be-deleted paths are checked whether they start with the vendor-packages +path. normalize_path is used mainly to correctly resolve symlinks. + +This patch only helps as long as `pip` itself is not upgraded. If that happens +then there are two installed versions of `pip`, one in each of +`{site,vendor}-packages` and the new, unpatched, `pip` will start to be used. + +To protect against that, we also patch `pip` to stop prompting users to +upgrade it, and to disallow updates of itself. + +Furthermore the system packages are installed in such a way that pip will not +remove them since it thinks they were installed with distutils. See +python_vendor_relocate() in lib/functions.sh for more details. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/pip/_internal/cli/cmdoptions.py a/src/pip/_internal/cli/cmdoptions.py +--- a~/src/pip/_internal/cli/cmdoptions.py 1970-01-01 00:00:00 ++++ a/src/pip/_internal/cli/cmdoptions.py 1970-01-01 00:00:00 +@@ -892,7 +892,7 @@ disable_pip_version_check: Callable[..., + "--disable-pip-version-check", + dest="disable_pip_version_check", + action="store_true", +- default=False, ++ default=True, + help="Don't periodically check PyPI to determine whether a new version " + "of pip is available for download. Implied with --no-index.", + ) +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/pip/_internal/exceptions.py a/src/pip/_internal/exceptions.py +--- a~/src/pip/_internal/exceptions.py 1970-01-01 00:00:00 ++++ a/src/pip/_internal/exceptions.py 1970-01-01 00:00:00 +@@ -771,9 +771,8 @@ class LegacyDistutilsInstall(DiagnosticP + super().__init__( + message=Text(f"Cannot uninstall {distribution}"), + context=( +- "It is a distutils installed project and thus we cannot accurately " +- "determine which files belong to it which would lead to only a partial " +- "uninstall." ++ "It is an IPS-managed package.\n" ++ "Use the system 'pkg' command instead." + ), + hint_stmt=None, + ) +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/pip/_internal/req/req_uninstall.py a/src/pip/_internal/req/req_uninstall.py +--- a~/src/pip/_internal/req/req_uninstall.py 1970-01-01 00:00:00 ++++ a/src/pip/_internal/req/req_uninstall.py 1970-01-01 00:00:00 +@@ -313,6 +313,15 @@ class UninstallPathSet: + remove/modify, False otherwise. + + """ ++ # Omit the vendor-packages augmentation to site-packages ++ # only when uninstalling. We want OmniOS IPS delivered packages ++ # in vendor-packages to be able to satisfy install dependencies ++ # but pip should never remove them. ++ vendor_packages_path = '/usr/lib/python{}.{}/vendor-packages'.format( ++ sys.version_info.major, sys.version_info.minor) ++ if normalize_path(path).startswith(vendor_packages_path): ++ return False ++ + # aka is_local, but caching normalized sys.prefix + if not running_under_virtualenv(): + return True +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/pip/_internal/self_outdated_check.py a/src/pip/_internal/self_outdated_check.py +--- a~/src/pip/_internal/self_outdated_check.py 1970-01-01 00:00:00 ++++ a/src/pip/_internal/self_outdated_check.py 1970-01-01 00:00:00 +@@ -228,6 +228,7 @@ def pip_self_version_check(session: PipS + the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix + of the pip script path. + """ ++ return + installed_dist = get_default_environment().get_distribution("pip") + if not installed_dist: + return diff --git a/build/python313/pip/patches/series b/build/python313/pip/patches/series new file mode 100644 index 0000000000..b779384136 --- /dev/null +++ b/build/python313/pip/patches/series @@ -0,0 +1,2 @@ +protect-vendor-packages.patch +system-certificates.patch diff --git a/build/python313/pip/patches/system-certificates.patch b/build/python313/pip/patches/system-certificates.patch new file mode 100644 index 0000000000..eb7fe50786 --- /dev/null +++ b/build/python313/pip/patches/system-certificates.patch @@ -0,0 +1,120 @@ +Patch originally from https://github.com/oracle/solaris-userland/ + +PIP on OmniOS should not use its bundled cacert.pem file, it should instead +use system certificates file which is more likely to be updated in a timely +manner when a CA cert is added/removed/modified. + +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/pip/_vendor/certifi/core.py a/src/pip/_vendor/certifi/core.py +--- a~/src/pip/_vendor/certifi/core.py 1970-01-01 00:00:00 ++++ a/src/pip/_vendor/certifi/core.py 1970-01-01 00:00:00 +@@ -10,105 +10,10 @@ import atexit + def exit_cacert_ctx() -> None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + ++def where() -> str: #keepindent ++ return "/etc/ssl/cacert.pem" + +-if sys.version_info >= (3, 11): ++def contents() -> str: #keepindent ++ with open(where(), "r", encoding="ascii") as fh: ++ return fh.read() + +- from importlib.resources import as_file, files +- +- _CACERT_CTX = None +- _CACERT_PATH = None +- +- def where() -> str: +- # This is slightly terrible, but we want to delay extracting the file +- # in cases where we're inside of a zipimport situation until someone +- # actually calls where(), but we don't want to re-extract the file +- # on every call of where(), so we'll do it once then store it in a +- # global variable. +- global _CACERT_CTX +- global _CACERT_PATH +- if _CACERT_PATH is None: +- # This is slightly janky, the importlib.resources API wants you to +- # manage the cleanup of this file, so it doesn't actually return a +- # path, it returns a context manager that will give you the path +- # when you enter it and will do any cleanup when you leave it. In +- # the common case of not needing a temporary file, it will just +- # return the file system location and the __exit__() is a no-op. +- # +- # We also have to hold onto the actual context manager, because +- # it will do the cleanup whenever it gets garbage collected, so +- # we will also store that at the global level as well. +- _CACERT_CTX = as_file(files("pip._vendor.certifi").joinpath("cacert.pem")) +- _CACERT_PATH = str(_CACERT_CTX.__enter__()) +- atexit.register(exit_cacert_ctx) +- +- return _CACERT_PATH +- +- def contents() -> str: +- return files("pip._vendor.certifi").joinpath("cacert.pem").read_text(encoding="ascii") +- +-elif sys.version_info >= (3, 7): +- +- from importlib.resources import path as get_path, read_text +- +- _CACERT_CTX = None +- _CACERT_PATH = None +- +- def where() -> str: +- # This is slightly terrible, but we want to delay extracting the +- # file in cases where we're inside of a zipimport situation until +- # someone actually calls where(), but we don't want to re-extract +- # the file on every call of where(), so we'll do it once then store +- # it in a global variable. +- global _CACERT_CTX +- global _CACERT_PATH +- if _CACERT_PATH is None: +- # This is slightly janky, the importlib.resources API wants you +- # to manage the cleanup of this file, so it doesn't actually +- # return a path, it returns a context manager that will give +- # you the path when you enter it and will do any cleanup when +- # you leave it. In the common case of not needing a temporary +- # file, it will just return the file system location and the +- # __exit__() is a no-op. +- # +- # We also have to hold onto the actual context manager, because +- # it will do the cleanup whenever it gets garbage collected, so +- # we will also store that at the global level as well. +- _CACERT_CTX = get_path("pip._vendor.certifi", "cacert.pem") +- _CACERT_PATH = str(_CACERT_CTX.__enter__()) +- atexit.register(exit_cacert_ctx) +- +- return _CACERT_PATH +- +- def contents() -> str: +- return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii") +- +-else: +- import os +- import types +- from typing import Union +- +- Package = Union[types.ModuleType, str] +- Resource = Union[str, "os.PathLike"] +- +- # This fallback will work for Python versions prior to 3.7 that lack the +- # importlib.resources module but relies on the existing `where` function +- # so won't address issues with environments like PyOxidizer that don't set +- # __file__ on modules. +- def read_text( +- package: Package, +- resource: Resource, +- encoding: str = 'utf-8', +- errors: str = 'strict' +- ) -> str: +- with open(where(), encoding=encoding) as data: +- return data.read() +- +- # If we don't have importlib.resources, then we will just do the old logic +- # of assuming we're on the filesystem and munge the path directly. +- def where() -> str: +- f = os.path.dirname(__file__) +- +- return os.path.join(f, "cacert.pem") +- +- def contents() -> str: +- return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii") diff --git a/build/python313/pycodestyle/build.sh b/build/python313/pycodestyle/build.sh new file mode 100755 index 0000000000..f70aad3848 --- /dev/null +++ b/build/python313/pycodestyle/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/pycodestyle-313 +PROG=pycodestyle +inherit_ver python312/pycodestyle +SUMMARY="$PROG - Python style guide checker" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pycodestyle/local.mog b/build/python313/pycodestyle/local.mog new file mode 100644 index 0000000000..51de1956ed --- /dev/null +++ b/build/python313/pycodestyle/local.mog @@ -0,0 +1,22 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + + set pkg.depend.bypass-generate .*> + + \ + edit path usr/bin usr/lib/python$(PYTHONVER)/bin > + +link path=usr/bin/pycodestyle target=../lib/python$(PYTHONVER)/bin/pycodestyle \ + mediator=python3 mediator-version=$(PYTHONVER) + diff --git a/build/python313/pycparser/build.sh b/build/python313/pycparser/build.sh new file mode 100755 index 0000000000..b1983580ab --- /dev/null +++ b/build/python313/pycparser/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/pycparser-313 +PROG=pycparser +inherit_ver python312/pycparser +SUMMARY="Complete parser of the C language" +DESC="$SUMMARY, written in pure Python" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pycparser/local.mog b/build/python313/pycparser/local.mog new file mode 100644 index 0000000000..db223b98c6 --- /dev/null +++ b/build/python313/pycparser/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2018 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=modified-BSD + diff --git a/build/python313/pycurl/build.sh b/build/python313/pycurl/build.sh new file mode 100755 index 0000000000..b5f3728871 --- /dev/null +++ b/build/python313/pycurl/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/pycurl-313 +PROG=pycurl +inherit_ver python312/pycurl +SUMMARY="Python bindings for libcurl" +DESC="PycURL provides a thin layer of Python bindings on top of libcurl." + +. $SRCDIR/../common.sh + +SKIP_LICENCES=MIT + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pycurl/local.mog b/build/python313/pycurl/local.mog new file mode 100644 index 0000000000..d6bb21caf2 --- /dev/null +++ b/build/python313/pycurl/local.mog @@ -0,0 +1,17 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license COPYING-LGPL license=LGPLv2.1 +license COPYING-MIT license=MIT + + drop> + diff --git a/build/python313/pycurl/patches/python313.patch b/build/python313/pycurl/patches/python313.patch new file mode 100644 index 0000000000..a84dd720eb --- /dev/null +++ b/build/python313/pycurl/patches/python313.patch @@ -0,0 +1,67 @@ + +THe Py_TRASHCAN_SAFE_BEGIN/END macros were deprecated in 3.11 and removed in +3.13. + +https://github.com/python/cpython/issues/105111 + +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/easy.c a/src/easy.c +--- a~/src/easy.c 1970-01-01 00:00:00 ++++ a/src/easy.c 1970-01-01 00:00:00 +@@ -280,13 +280,13 @@ PYCURL_INTERNAL void + do_curl_dealloc(CurlObject *self) + { + PyObject_GC_UnTrack(self); +- Py_TRASHCAN_SAFE_BEGIN(self); ++ Py_TRASHCAN_BEGIN(self, __func__); + + Py_CLEAR(self->dict); + util_curl_close(self); + + Curl_Type.tp_free(self); +- Py_TRASHCAN_SAFE_END(self); ++ Py_TRASHCAN_END; + } + + +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/multi.c a/src/multi.c +--- a~/src/multi.c 1970-01-01 00:00:00 ++++ a/src/multi.c 1970-01-01 00:00:00 +@@ -117,7 +117,7 @@ PYCURL_INTERNAL void + do_multi_dealloc(CurlMultiObject *self) + { + PyObject_GC_UnTrack(self); +- Py_TRASHCAN_SAFE_BEGIN(self); ++ Py_TRASHCAN_BEGIN(self, __func__); + + util_multi_xdecref(self); + util_multi_close(self); +@@ -127,7 +127,7 @@ do_multi_dealloc(CurlMultiObject *self) + } + + CurlMulti_Type.tp_free(self); +- Py_TRASHCAN_SAFE_END(self); ++ Py_TRASHCAN_END; + } + + +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/share.c a/src/share.c +--- a~/src/share.c 1970-01-01 00:00:00 ++++ a/src/share.c 1970-01-01 00:00:00 +@@ -119,7 +119,7 @@ PYCURL_INTERNAL void + do_share_dealloc(CurlShareObject *self) + { + PyObject_GC_UnTrack(self); +- Py_TRASHCAN_SAFE_BEGIN(self); ++ Py_TRASHCAN_BEGIN(self, __func__); + + Py_CLEAR(self->dict); + util_share_close(self); +@@ -133,7 +133,7 @@ do_share_dealloc(CurlShareObject *self) + } + + CurlShare_Type.tp_free(self); +- Py_TRASHCAN_SAFE_END(self); ++ Py_TRASHCAN_END; + } + + diff --git a/build/python313/pycurl/patches/series b/build/python313/pycurl/patches/series new file mode 100644 index 0000000000..3231737c5c --- /dev/null +++ b/build/python313/pycurl/patches/series @@ -0,0 +1 @@ +python313.patch diff --git a/build/python313/pycurl/test b/build/python313/pycurl/test new file mode 100755 index 0000000000..dd89a19a79 --- /dev/null +++ b/build/python313/pycurl/test @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import pycurl +from io import BytesIO + +buffer = BytesIO() +c = pycurl.Curl() +c.setopt(c.URL, 'https://omnios.org/') +c.setopt(c.WRITEDATA, buffer) +c.perform() +c.close() + +body = buffer.getvalue() +# Body is a byte string. +# We have to know the encoding in order to print it to a text file +# such as standard output. +print(body.decode('iso-8859-1')) + diff --git a/build/python313/pyopenssl/build.sh b/build/python313/pyopenssl/build.sh new file mode 100755 index 0000000000..1c0213dbb5 --- /dev/null +++ b/build/python313/pyopenssl/build.sh @@ -0,0 +1,40 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/pyopenssl-313 +PROG=pyopenssl +inherit_ver python312/pyopenssl +SUMMARY="pyOpenSSL - Python interface to the OpenSSL library" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +RUN_DEPENDS_IPS+=" library/python-$PYMVER/cryptography-$SPYVER" + +[ "$BUILDARCH" = aarch64 ] && set_patchdir patches.aarch64 + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pyopenssl/local.mog b/build/python313/pyopenssl/local.mog new file mode 100644 index 0000000000..bc7ff1a3b1 --- /dev/null +++ b/build/python313/pyopenssl/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2018 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=Apache2 + diff --git a/build/python313/pyopenssl/patches.aarch64/cryptography.patch b/build/python313/pyopenssl/patches.aarch64/cryptography.patch new file mode 100644 index 0000000000..6a639c30f8 --- /dev/null +++ b/build/python313/pyopenssl/patches.aarch64/cryptography.patch @@ -0,0 +1,81 @@ +diff -wpruN --no-dereference '--exclude=*.orig' a~/src/OpenSSL/crypto.py a/src/OpenSSL/crypto.py +--- a~/src/OpenSSL/crypto.py 1970-01-01 00:00:00 ++++ a/src/OpenSSL/crypto.py 1970-01-01 00:00:00 +@@ -968,7 +968,6 @@ utils.deprecated( + "APIs in cryptography." + ), + DeprecationWarning, +- name="X509Extension", + ) + + +@@ -1203,7 +1202,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="X509Req", + ) + + +@@ -2400,7 +2398,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="Revoked", + ) + + +@@ -2645,7 +2642,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="CRL", + ) + + +@@ -2840,7 +2836,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="dump_certificate_request", + ) + + +@@ -2882,7 +2877,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="load_certificate_request", + ) + + +@@ -2926,7 +2920,6 @@ utils.deprecated( + __name__, + "sign() is deprecated. Use the equivalent APIs in cryptography.", + DeprecationWarning, +- name="sign", + ) + + +@@ -2973,7 +2966,6 @@ utils.deprecated( + __name__, + "verify() is deprecated. Use the equivalent APIs in cryptography.", + DeprecationWarning, +- name="verify", + ) + + +@@ -3015,7 +3007,6 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="dump_crl", + ) + + +@@ -3058,5 +3049,4 @@ utils.deprecated( + "in cryptography." + ), + DeprecationWarning, +- name="load_crl", + ) diff --git a/build/python313/pyopenssl/patches.aarch64/series b/build/python313/pyopenssl/patches.aarch64/series new file mode 100644 index 0000000000..30d70d2afc --- /dev/null +++ b/build/python313/pyopenssl/patches.aarch64/series @@ -0,0 +1 @@ +cryptography.patch diff --git a/build/python313/pyopenssl/test b/build/python313/pyopenssl/test new file mode 100755 index 0000000000..438ef9d959 --- /dev/null +++ b/build/python313/pyopenssl/test @@ -0,0 +1,9 @@ +#!/usr/bin/python3 + +from OpenSSL import crypto + +TYPE_RSA = crypto.TYPE_RSA + +pkey = crypto.PKey() +pkey.generate_key(TYPE_RSA, 2048) + diff --git a/build/python313/pyrsistent/build.sh b/build/python313/pyrsistent/build.sh new file mode 100755 index 0000000000..b043e9accf --- /dev/null +++ b/build/python313/pyrsistent/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/pyrsistent-313 +PROG=pyrsistent +inherit_ver python312/pyrsistent +SUMMARY="Python pyrsistent" +DESC="Persistent/Functional/Immutable data structures" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pyrsistent/local.mog b/build/python313/pyrsistent/local.mog new file mode 100644 index 0000000000..63c3c44e4c --- /dev/null +++ b/build/python313/pyrsistent/local.mog @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE.mit license=MIT + + edit path usr/bin usr/lib/python$(PYTHONVER)/bin> + diff --git a/build/python313/pyyaml/build.sh b/build/python313/pyyaml/build.sh new file mode 100755 index 0000000000..e8bef9ead9 --- /dev/null +++ b/build/python313/pyyaml/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/pyyaml-313 +PROG=pyyaml +inherit_ver python312/pyyaml +SUMMARY="YAML parser and emitter for Python" +DESC="YAML is a data serialization format designed for human readability " +DESC+="and interaction with scripting languages. " +DESC+="PyYAML is a YAML parser and emitter for Python." + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/pyyaml/local.mog b/build/python313/pyyaml/local.mog new file mode 100644 index 0000000000..66d3bacd93 --- /dev/null +++ b/build/python313/pyyaml/local.mog @@ -0,0 +1,15 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/rapidjson/build.sh b/build/python313/rapidjson/build.sh new file mode 100755 index 0000000000..e6ecf715b3 --- /dev/null +++ b/build/python313/rapidjson/build.sh @@ -0,0 +1,41 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. +# +. ../../../lib/build.sh + +PKG=library/python-3/rapidjson-313 +PROG=rapidjson +inherit_ver python312/rapidjson +SUMMARY="rapidjson - Python interface to RapidJSON" +DESC="RapidJSON is an extremely fast C++ JSON parser and serialization library" +DESC+="; this module wraps it into a Python 3 extension" + +. $SRCDIR/../common.sh + +CFLAGS[aarch64]+=" -fpermissive" + +set_builddir python_$PROG-$VER + +init +download_source pymodules/$PROG python_$PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/rapidjson/local.mog b/build/python313/rapidjson/local.mog new file mode 100644 index 0000000000..dbe1574ad3 --- /dev/null +++ b/build/python313/rapidjson/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/rapidjson/patches/hexdigits.patch b/build/python313/rapidjson/patches/hexdigits.patch new file mode 100644 index 0000000000..3dd691a4b8 --- /dev/null +++ b/build/python313/rapidjson/patches/hexdigits.patch @@ -0,0 +1,16 @@ + +For compatibility with simplejson, output lower case hex digits for dump[s]() +with ensure_ascii=True + +diff -wpruN --no-dereference '--exclude=*.orig' a~/rapidjson/include/rapidjson/writer.h a/rapidjson/include/rapidjson/writer.h +--- a~/rapidjson/include/rapidjson/writer.h 1970-01-01 00:00:00 ++++ a/rapidjson/include/rapidjson/writer.h 1970-01-01 00:00:00 +@@ -381,7 +381,7 @@ protected: + } + + bool WriteString(const Ch* str, SizeType length) { +- static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; ++ static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + static const char escape[256] = { + #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F diff --git a/build/python313/rapidjson/patches/series b/build/python313/rapidjson/patches/series new file mode 100644 index 0000000000..ef65a115d2 --- /dev/null +++ b/build/python313/rapidjson/patches/series @@ -0,0 +1 @@ +hexdigits.patch diff --git a/build/python313/rapidjson/test b/build/python313/rapidjson/test new file mode 100755 index 0000000000..f2a152830d --- /dev/null +++ b/build/python313/rapidjson/test @@ -0,0 +1,5 @@ +#!/usr/bin/python3 + +import rapidjson as json +print(json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])) + diff --git a/build/python313/semantic-version/build.sh b/build/python313/semantic-version/build.sh new file mode 100755 index 0000000000..3a77b3e7d4 --- /dev/null +++ b/build/python313/semantic-version/build.sh @@ -0,0 +1,37 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/semantic-version-313 +PROG=semantic_version +inherit_ver python312/semantic-version +SUMMARY="A library implementing the 'SemVer' scheme." +DESC="This small python library provides a few tools to handle SemVer in " +DESC+="Python. It follows strictly the 2.0.0 version of the SemVer scheme." + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package $SRCDIR/../common.mog +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/semantic-version/local.mog b/build/python313/semantic-version/local.mog new file mode 100644 index 0000000000..82f8802c50 --- /dev/null +++ b/build/python313/semantic-version/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=simplified-BSD + diff --git a/build/python313/setuptools-rust/build.sh b/build/python313/setuptools-rust/build.sh new file mode 100755 index 0000000000..abbf53887c --- /dev/null +++ b/build/python313/setuptools-rust/build.sh @@ -0,0 +1,44 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/setuptools-rust-313 +PROG=setuptools_rust +inherit_ver python312/setuptools-rust +SUMMARY="Python setuptools rust extension plugin" +DESC="Compile and distribute Python extensions written in rust as easily " +DESC+="as if they were written in C." + +. $SRCDIR/../common.sh + +RUN_DEPENDS_IPS+=" + library/python-$PYMVER/setuptools-$SPYVER + library/python-$PYMVER/semantic-version-$SPYVER + library/python-$PYMVER/tomli-$SPYVER + library/python-$PYMVER/typing-extensions-$SPYVER +" + +init +download_source pymodules/${PROG/_/-} $PROG-$VER +patch_source +prep_build +python_build +make_package $SRCDIR/../common.mog +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/setuptools-rust/local.mog b/build/python313/setuptools-rust/local.mog new file mode 100644 index 0000000000..123002c31e --- /dev/null +++ b/build/python313/setuptools-rust/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/setuptools/build.sh b/build/python313/setuptools/build.sh new file mode 100755 index 0000000000..722f33e9ef --- /dev/null +++ b/build/python313/setuptools/build.sh @@ -0,0 +1,45 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/setuptools-313 +PROG=setuptools +inherit_ver python312/setuptools +SUMMARY="Python package management" +DESC="Easily download, build, install, upgrade, and uninstall Python packages" + +. $SRCDIR/../common.sh + +if [ "$FLAVOR" = bootstrap ]; then + # When bootstrapping a new python version, we need to break the cyclic + # dependency between setuptools and pip. Build without pip and do not add + # the dependency. + PYTHON_BUILD_BACKEND=setuppy +else + RUN_DEPENDS_IPS+=" library/python-$PYMVER/pip-$SPYVER" +fi + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package $SRCDIR/../common.mog +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/setuptools/local.mog b/build/python313/setuptools/local.mog new file mode 100644 index 0000000000..b13adfe135 --- /dev/null +++ b/build/python313/setuptools/local.mog @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + + set pkg.depend.bypass-generate .*> + \ + edit path usr/bin usr/lib/python$(PYTHONVER)/bin > + diff --git a/build/python313/six/build.sh b/build/python313/six/build.sh new file mode 100755 index 0000000000..cc82df5ab7 --- /dev/null +++ b/build/python313/six/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} + +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/six-313 +PROG=six +inherit_ver python312/six +SUMMARY="A Python 2 and 3 compatibility library" +DESC="$SUMMARY" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/six/local.mog b/build/python313/six/local.mog new file mode 100644 index 0000000000..8db201d6fe --- /dev/null +++ b/build/python313/six/local.mog @@ -0,0 +1,14 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/testsuite-d.log b/build/python313/testsuite-d.log new file mode 100644 index 0000000000..9ece5cf570 --- /dev/null +++ b/build/python313/testsuite-d.log @@ -0,0 +1,7 @@ +== Tests result: SUCCESS == + +1 test OK. + +Total tests: run=8 skipped=5 +Total test files: run=1/1 +Result: SUCCESS diff --git a/build/python313/testsuite.log b/build/python313/testsuite.log new file mode 100644 index 0000000000..96a10893fd --- /dev/null +++ b/build/python313/testsuite.log @@ -0,0 +1,22 @@ +== Tests result: SUCCESS == + +27 tests skipped: + test.test_asyncio.test_windows_events + test.test_asyncio.test_windows_utils test.test_gdb.test_backtrace + test.test_gdb.test_cfunction test.test_gdb.test_cfunction_full + test.test_gdb.test_misc test.test_gdb.test_pretty_print + test_android test_dbm_gnu test_epoll test_free_threading test_idle + test_kqueue test_launcher test_msvcrt test_perf_profiler + test_perfmaps test_startfile test_tcl test_tkinter test_ttk + test_ttk_textonly test_turtle test_winapi test_winconsoleio + test_winreg test_wmi + +6 tests skipped (resource denied): + test_smtpnet test_socketserver test_urllib2net test_urllibnet + test_winsound test_zipfile64 + +445 tests OK. + +Total tests: run=44,074 (filtered) skipped=1,955 +Total test files: run=472/478 (filtered) skipped=27 resource_denied=6 +Result: SUCCESS diff --git a/build/python313/tomli/build.sh b/build/python313/tomli/build.sh new file mode 100755 index 0000000000..ccbb882224 --- /dev/null +++ b/build/python313/tomli/build.sh @@ -0,0 +1,36 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/tomli-313 +PROG=tomli +inherit_ver python312/tomli +SUMMARY="Python TOML parser" +DESC="Tomli is a Python library for parsing TOML" + +. $SRCDIR/../common.sh + +init +download_source pymodules/$PROG $PROG $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/tomli/local.mog b/build/python313/tomli/local.mog new file mode 100644 index 0000000000..3e1798fe81 --- /dev/null +++ b/build/python313/tomli/local.mog @@ -0,0 +1,13 @@ +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=MIT + diff --git a/build/python313/typing-extensions/build.sh b/build/python313/typing-extensions/build.sh new file mode 100755 index 0000000000..826f909452 --- /dev/null +++ b/build/python313/typing-extensions/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/bash +# +# {{{ CDDL HEADER +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# }}} +# +# Copyright 2024 OmniOS Community Edition (OmniOSce) Association. + +. ../../../lib/build.sh + +PKG=library/python-3/typing-extensions-313 +PROG=typing-extensions +inherit_ver python312/typing-extensions +SUMMARY="Python typing extensions" +DESC="Backported and Experimental Type Hints for Python 3.6+" + +. $SRCDIR/../common.sh + +set_builddir ${PROG/-/_}-$VER + +init +download_source pymodules/$PROG ${PROG/-/_} $VER +patch_source +prep_build +python_build +make_package +clean_up + +# Vim hints +# vim:ts=4:sw=4:et:fdm=marker diff --git a/build/python313/typing-extensions/local.mog b/build/python313/typing-extensions/local.mog new file mode 100644 index 0000000000..79653a6d2f --- /dev/null +++ b/build/python313/typing-extensions/local.mog @@ -0,0 +1,16 @@ +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. + +# Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + +license LICENSE license=PSFv2 + + edit path /src_py3/ /> + drop> + diff --git a/doc/baseline b/doc/baseline index ff71dddcb3..cea3d1a6cc 100644 --- a/doc/baseline +++ b/doc/baseline @@ -295,57 +295,84 @@ omnios library/print/open-printing/lpd omnios library/python-2/setuptools-27 omnios library/python-3/asn1crypto-311 o omnios library/python-3/asn1crypto-312 +omnios library/python-3/asn1crypto-313 omnios library/python-3/attrs-311 o omnios library/python-3/attrs-312 +omnios library/python-3/attrs-313 omnios library/python-3/cffi-311 o omnios library/python-3/cffi-312 +omnios library/python-3/cffi-313 omnios library/python-3/coverage-311 o omnios library/python-3/coverage-312 +omnios library/python-3/coverage-313 omnios library/python-3/crossenv-311 o omnios library/python-3/crossenv-312 +omnios library/python-3/crossenv-313 omnios library/python-3/cryptography-311 o omnios library/python-3/cryptography-312 +omnios library/python-3/cryptography-313 omnios library/python-3/idna-311 o omnios library/python-3/idna-312 +omnios library/python-3/idna-313 omnios library/python-3/js-regex-311 o omnios library/python-3/js-regex-312 +omnios library/python-3/js-regex-313 omnios library/python-3/jsonrpclib-311 o omnios library/python-3/jsonrpclib-312 +omnios library/python-3/jsonrpclib-313 omnios library/python-3/jsonschema-311 o omnios library/python-3/jsonschema-312 +omnios library/python-3/jsonschema-313 omnios library/python-3/meson-311 o omnios library/python-3/meson-312 +omnios library/python-3/meson-313 omnios library/python-3/orjson-311 o omnios library/python-3/orjson-312 +omnios library/python-3/orjson-313 omnios library/python-3/packaging-312 +omnios library/python-3/packaging-313 omnios library/python-3/pip-311 o omnios library/python-3/pip-312 +omnios library/python-3/pip-313 omnios library/python-3/pycodestyle-311 o omnios library/python-3/pycodestyle-312 +omnios library/python-3/pycodestyle-313 omnios library/python-3/pycparser-311 o omnios library/python-3/pycparser-312 +omnios library/python-3/pycparser-313 omnios library/python-3/pycurl-311 o omnios library/python-3/pycurl-312 +omnios library/python-3/pycurl-313 omnios library/python-3/pyopenssl-311 o omnios library/python-3/pyopenssl-312 +omnios library/python-3/pyopenssl-313 omnios library/python-3/pyrsistent-311 o omnios library/python-3/pyrsistent-312 +omnios library/python-3/pyrsistent-313 omnios library/python-3/pyyaml-311 o omnios library/python-3/pyyaml-312 +omnios library/python-3/pyyaml-313 omnios library/python-3/rapidjson-311 o omnios library/python-3/rapidjson-312 +omnios library/python-3/rapidjson-313 omnios library/python-3/semantic-version-311 o omnios library/python-3/semantic-version-312 +omnios library/python-3/semantic-version-313 omnios library/python-3/setuptools-311 o omnios library/python-3/setuptools-312 +omnios library/python-3/setuptools-313 omnios library/python-3/setuptools-rust-311 o omnios library/python-3/setuptools-rust-312 +omnios library/python-3/setuptools-rust-313 omnios library/python-3/six-311 o omnios library/python-3/six-312 +omnios library/python-3/six-313 omnios library/python-3/tomli-311 o omnios library/python-3/tomli-312 +omnios library/python-3/tomli-313 omnios library/python-3/typing-extensions-311 o omnios library/python-3/typing-extensions-312 +omnios library/python-3/typing-extensions-313 omnios library/readline omnios library/security/liboqs omnios library/security/openssl @@ -512,6 +539,7 @@ omnios runtime/perl/module/sun-solaris omnios runtime/python-27 l omnios runtime/python-311 r omnios runtime/python-312 +omnios runtime/python-313 omnios security/bart omnios security/sudo omnios service/fault-management @@ -668,12 +696,15 @@ omnios system/library/processor o omnios system/library/python/libbe-27 o omnios system/library/python/libbe-311 o omnios system/library/python/libbe-312 +omnios system/library/python/libbe-313 omnios system/library/python/solaris-27 o omnios system/library/python/solaris-311 o omnios system/library/python/solaris-312 +omnios system/library/python/solaris-313 omnios system/library/python/zfs-27 o omnios system/library/python/zfs-311 o omnios system/library/python/zfs-312 +omnios system/library/python/zfs-313 omnios system/library/security/crypto/pkcs11_kms o omnios system/library/security/gss omnios system/library/security/gss/diffie-hellman diff --git a/doc/packages.md b/doc/packages.md index b48502ba1d..644e803dd0 100644 --- a/doc/packages.md +++ b/doc/packages.md @@ -82,6 +82,7 @@ | runtime/perl | 5.40.0 | https://www.cpan.org/src/README.html | runtime/python-311 | 3.11.11 | https://www.python.org/downloads/source/ | runtime/python-312 | 3.12.8 | https://www.python.org/downloads/source/ +| runtime/python-313 | 3.13.1 | https://www.python.org/downloads/source/ | security/sudo | 1.9.16p2 | https://www.sudo.ws/ | service/network/chrony | 4.5 | https://download.tuxfamily.org/chrony/ | service/network/ntpsec | 1.2.3 | https://github.com/ntpsec/ntpsec/tags https://blog.ntpsec.org/ @@ -126,31 +127,31 @@ | system/virtualization/open-vm-tools | 12.5.0 | https://github.com/vmware/open-vm-tools/releases https://docs.vmware.com/en/VMware-Tools/ | developer/swig | 4.3.0 | http://www.swig.org/download.html | library/security/trousers | 0.3.15 | https://sourceforge.net/projects/trousers/files/trousers -| library/python-3/asn1crypto-312 | 1.5.1 | https://pypi.org/project/asn1crypto -| library/python-3/attrs-312 | 24.2.0 | https://pypi.org/project/attrs -| library/python-3/cffi-312 | 1.17.1 | https://pypi.org/project/cffi -| library/python-3/coverage-312 | 7.6.4 | https://pypi.org/project/coverage -| library/python-3/crossenv-312 | 1.5.0 | https://pypi.org/project/crossenv -| library/python-3/cryptography-312 | 43.0.3 | https://pypi.org/project/cryptography -| library/python-3/idna-312 | 3.10 | https://pypi.org/project/idna -| library/python-3/js-regex-312 | 1.0.1 | https://pypi.org/project/js-regex -| library/python-3/jsonrpclib-312 | 0.4.3.3 | https://github.com/tcalmant/jsonrpclib/releases -| library/python-3/jsonschema-312 | 4.17.3 | https://pypi.org/project/jsonschema -| library/python-3/meson-312 | 1.6.0 | https://github.com/mesonbuild/meson/releases https://mesonbuild.com/ -| library/python-3/orjson-312 | 3.10.11 | https://github.com/ijl/orjson/releases -| library/python-3/packaging-312 | 24.2 | https://pypi.org/project/packaging -| library/python-3/pip-312 | 24.3.1 | https://pypi.org/project/pip -| library/python-3/pycodestyle-312 | 2.12.1 | https://pypi.org/project/pycodestyle/ -| library/python-3/pycparser-312 | 2.22 | https://pypi.org/project/pycparser -| library/python-3/pycurl-312 | 7.44.1 | https://pypi.org/project/pycurl -| library/python-3/pyopenssl-312 | 24.2.1 | https://pypi.org/project/pyOpenSSL -| library/python-3/pyrsistent-312 | 0.20.0 | https://pypi.org/project/pyrsistent -| library/python-3/pyyaml-312 | 6.0.2 | https://pypi.org/project/PyYAML -| library/python-3/rapidjson-312 | 1.20 | https://pypi.org/project/python-rapidjson -| library/python-3/semantic-version-312 | 2.10.0 | https://pypi.org/project/semantic-version -| library/python-3/setuptools-312 | 75.4.0 | https://pypi.org/project/setuptools -| library/python-3/setuptools-rust-312 | 1.10.2 | https://pypi.org/project/setuptools-rust -| library/python-3/six-312 | 1.16.0 | https://pypi.org/project/six -| library/python-3/tomli-312 | 2.1.0 | https://pypi.org/project/tomli -| library/python-3/typing-extensions-312| 4.12.2 | https://pypi.org/project/typing-extensions +| library/python-3/asn1crypto-313 | 1.5.1 | https://pypi.org/project/asn1crypto +| library/python-3/attrs-313 | 24.2.0 | https://pypi.org/project/attrs +| library/python-3/cffi-313 | 1.17.1 | https://pypi.org/project/cffi +| library/python-3/coverage-313 | 7.6.4 | https://pypi.org/project/coverage +| library/python-3/crossenv-313 | 1.5.0 | https://pypi.org/project/crossenv +| library/python-3/cryptography-313 | 43.0.3 | https://pypi.org/project/cryptography +| library/python-3/idna-313 | 3.10 | https://pypi.org/project/idna +| library/python-3/js-regex-313 | 1.0.1 | https://pypi.org/project/js-regex +| library/python-3/jsonrpclib-313 | 0.4.3.3 | https://github.com/tcalmant/jsonrpclib/releases +| library/python-3/jsonschema-313 | 4.17.3 | https://pypi.org/project/jsonschema +| library/python-3/meson-313 | 1.6.0 | https://github.com/mesonbuild/meson/releases https://mesonbuild.com/ +| library/python-3/orjson-313 | 3.10.11 | https://github.com/ijl/orjson/releases +| library/python-3/packaging-313 | 24.2 | https://pypi.org/project/packaging +| library/python-3/pip-313 | 24.3.1 | https://pypi.org/project/pip +| library/python-3/pycodestyle-313 | 2.12.1 | https://pypi.org/project/pycodestyle/ +| library/python-3/pycparser-313 | 2.22 | https://pypi.org/project/pycparser +| library/python-3/pycurl-313 | 7.44.1 | https://pypi.org/project/pycurl +| library/python-3/pyopenssl-313 | 24.2.1 | https://pypi.org/project/pyOpenSSL +| library/python-3/pyrsistent-313 | 0.20.0 | https://pypi.org/project/pyrsistent +| library/python-3/pyyaml-313 | 6.0.2 | https://pypi.org/project/PyYAML +| library/python-3/rapidjson-313 | 1.20 | https://pypi.org/project/python-rapidjson +| library/python-3/semantic-version-313 | 2.10.0 | https://pypi.org/project/semantic-version +| library/python-3/setuptools-313 | 75.4.0 | https://pypi.org/project/setuptools +| library/python-3/setuptools-rust-313 | 1.10.2 | https://pypi.org/project/setuptools-rust +| library/python-3/six-313 | 1.16.0 | https://pypi.org/project/six +| library/python-3/tomli-313 | 2.1.0 | https://pypi.org/project/tomli +| library/python-3/typing-extensions-313| 4.12.2 | https://pypi.org/project/typing-extensions