From f18164db89b1f3938ad868e6bd99b8dd1591ea2c Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 3 Jun 2024 18:30:19 +0100 Subject: [PATCH] [Static Linux] Add build scripts. Add the build scripts for the fully static Linux SDK. rdar://129171568 --- swift-ci/sdks/static-linux/Dockerfile | 97 ++ swift-ci/sdks/static-linux/README.md | 33 + swift-ci/sdks/static-linux/build | 32 + .../static-linux/resources/fts/CMakeLists.txt | 25 + .../sdks/static-linux/resources/fts/README.md | 48 + .../sdks/static-linux/resources/fts/VERSION | 1 + .../sdks/static-linux/resources/fts/config.h | 22 + .../sdks/static-linux/resources/fts/fts.3 | 773 ++++++++++ .../sdks/static-linux/resources/fts/fts.c | 1255 +++++++++++++++++ .../sdks/static-linux/resources/fts/fts.h | 157 +++ .../static-linux/resources/linux/capability.h | 59 + .../sdks/static-linux/resources/linux/futex.h | 71 + .../static-linux/resources/linux/limits.h | 22 + .../static-linux/resources/linux/random.h | 30 + .../static-linux/resources/linux/sockios.h | 24 + .../static-linux/resources/linux/vm_sockets.h | 49 + .../static-linux/resources/patches/musl.patch | 73 + swift-ci/sdks/static-linux/scripts/build.sh | 910 ++++++++++++ .../sdks/static-linux/scripts/fetch-source.sh | 217 +++ .../sdks/static-linux/scripts/fixtypes.py | 280 ++++ .../static-linux/scripts/install-swift.sh | 64 + 21 files changed, 4242 insertions(+) create mode 100644 swift-ci/sdks/static-linux/Dockerfile create mode 100644 swift-ci/sdks/static-linux/README.md create mode 100755 swift-ci/sdks/static-linux/build create mode 100644 swift-ci/sdks/static-linux/resources/fts/CMakeLists.txt create mode 100644 swift-ci/sdks/static-linux/resources/fts/README.md create mode 100644 swift-ci/sdks/static-linux/resources/fts/VERSION create mode 100644 swift-ci/sdks/static-linux/resources/fts/config.h create mode 100644 swift-ci/sdks/static-linux/resources/fts/fts.3 create mode 100644 swift-ci/sdks/static-linux/resources/fts/fts.c create mode 100644 swift-ci/sdks/static-linux/resources/fts/fts.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/capability.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/futex.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/limits.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/random.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/sockios.h create mode 100644 swift-ci/sdks/static-linux/resources/linux/vm_sockets.h create mode 100644 swift-ci/sdks/static-linux/resources/patches/musl.patch create mode 100755 swift-ci/sdks/static-linux/scripts/build.sh create mode 100755 swift-ci/sdks/static-linux/scripts/fetch-source.sh create mode 100755 swift-ci/sdks/static-linux/scripts/fixtypes.py create mode 100755 swift-ci/sdks/static-linux/scripts/install-swift.sh diff --git a/swift-ci/sdks/static-linux/Dockerfile b/swift-ci/sdks/static-linux/Dockerfile new file mode 100644 index 00000000..a8aa09d2 --- /dev/null +++ b/swift-ci/sdks/static-linux/Dockerfile @@ -0,0 +1,97 @@ +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Docker-based build +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +FROM ubuntu:22.04 + +# Versions to fetch + +ARG SWIFT_VERSION=scheme:release/6.0 +ARG MUSL_VERSION=1.2.5 +ARG LIBXML2_VERSION=2.12.7 +ARG CURL_VERSION=8.7.1 +ARG BORINGSSL_VERSION=fips-20220613 +ARG ICU_VERSION=maint/maint-69 +ARG ZLIB_VERSION=1.3.1 + +# ............................................................................ + +# Install development tools +RUN apt-get -q update \ + && DEBIAN_FRONTEND=noninteractive apt-get -q install -y \ + build-essential \ + cmake \ + ninja-build \ + python3 \ + golang \ + git \ + gnupg2 \ + libsqlite3-dev \ + libcurl4-openssl-dev \ + libedit-dev \ + libicu-dev \ + libncurses5-dev \ + libpython3-dev \ + libsqlite3-dev \ + libxml2-dev \ + uuid-dev \ + uuid-runtime \ + tzdata \ + curl \ + && rm -rf /var/lib/apt-lists/* + +# Install Swift +ARG SWIFT_SIGNING_KEY=E813C892820A6FA13755B268F167DF1ACF9CE069 +ARG SWIFT_PLATFORM=ubuntu +ARG OS_MAJOR_VER=22 +ARG OS_MINOR_VER=04 +ARG SWIFT_WEBROOT=https://download.swift.org/swift-6.0-branch + +ENV SWIFT_SIGNING_KEY=$SWIFT_SIGNING_KEY \ + SWIFT_PLATFORM=$SWIFT_PLATFORM \ + OS_MAJOR_VER=$OS_MAJOR_VER \ + OS_MINOR_VER=$OS_MINOR_VER \ + OS_VER=$SWIFT_PLATFORM$OS_MAJOR_VER.$OS_MINOR_VER \ + SWIFT_WEBROOT="$SWIFT_WEBROOT/$SWIFT_PLATFORM$OS_MAJOR_VER$OS_MINOR_VER" + +COPY scripts/install-swift.sh /scripts/install-swift.sh +RUN chmod ugo+x /scripts/install-swift.sh + +RUN /scripts/install-swift.sh + +ENV PATH="/usr/local/swift/bin:${PATH}" + +ENV SWIFT_VERSION=$SWIFT_VERSION \ + MUSL_VERSION=$MUSL_VERSION \ + LIBXML2_VERSION=$LIBXML2_VERSION \ + CURL_VERSION=$CURL_VERSION \ + BORINGSSL_VERSION=$BORINGSSL_VERSION \ + ICU_VERSION=$ICU_VERSION \ + ZLIB_VERSION=$ZLIB_VERSION + +COPY scripts /scripts +RUN chmod ugo+x /scripts/* + +COPY resources /resources + +# Create a user +RUN groupadd -g 998 build-user && \ + useradd -m -r -u 998 -g build-user build-user + +USER build-user + +WORKDIR /home/build-user + + + + diff --git a/swift-ci/sdks/static-linux/README.md b/swift-ci/sdks/static-linux/README.md new file mode 100644 index 00000000..3405b1f5 --- /dev/null +++ b/swift-ci/sdks/static-linux/README.md @@ -0,0 +1,33 @@ +# Dockerfile-based build for Swift Static Linux SDK + +## What is this? + +This is a Dockerfile-based build set-up for the Swift Static Linux SDK. + +To use it, you need to build the Docker image with + +```shell +$ docker build -t static-swift-linux . +``` + +then you can check-out the sources somewhere using + +```shell +$ scripts/fetch-source.sh --clone-with-ssh --source-dir /path/to/source +``` + +and finally use the Docker image to do your build + +```shell +$ mkdir /path/to/products +$ docker run -it --rm \ + -v /path/to/source:/source \ + -v /path/to/products:/products \ + static-swift-linux \ + /scripts/build.sh --source-dir /source --products-dir /products +``` + +The artifact bundle should appear at `/path/to/products`. + +The `scripts/build.sh` script has a number of options you may wish to +investigate. Similarly with the `scripts/fetch-source.sh` script. diff --git a/swift-ci/sdks/static-linux/build b/swift-ci/sdks/static-linux/build new file mode 100755 index 00000000..7bbc2bf0 --- /dev/null +++ b/swift-ci/sdks/static-linux/build @@ -0,0 +1,32 @@ +#!/bin/bash +# +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Top-level Build Script +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +DOCKER=docker + +# Build the Docker image +$(DOCKER) build -t static-swift-linux . + +# Check-out the sources +scripts/fetch-source.sh --clone-with-ssh --source-dir source + +mkdir -p products + +# Run the build +$(DOCKER) run -it --rm \ + -v ./source:/source \ + -v ./products:/products \ + static-swift-linux \ + /scripts/build.sh --source-dir /source --products-dir /products diff --git a/swift-ci/sdks/static-linux/resources/fts/CMakeLists.txt b/swift-ci/sdks/static-linux/resources/fts/CMakeLists.txt new file mode 100644 index 00000000..977d5f0a --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/CMakeLists.txt @@ -0,0 +1,25 @@ +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Build libfts +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +cmake_minimum_required(VERSION 3.22.1) + +project(fts) + +add_library(fts STATIC fts.c) +set_target_properties(fts PROPERTIES PUBLIC_HEADER fts.h) +target_include_directories(fts PRIVATE SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}) + +install(TARGETS fts + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/swift-ci/sdks/static-linux/resources/fts/README.md b/swift-ci/sdks/static-linux/resources/fts/README.md new file mode 100644 index 00000000..4f1f41e0 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/README.md @@ -0,0 +1,48 @@ +What is this? +============= + +Musl doesn't have fts in its libc. Alpine and other Musl-based +distributions typically provide an fts implementation separately, +using a derivative of NetBSD's fts, which is what you'll find in this +directory. + +Typically they use the one from https://github.com/void-linux/musl-fts +but that uses GNU autotools and annoyingly they haven't checked in the +generated configure script. Not that it actually *needs* a configure +script, because they know what C library they're using already. + +Anyway, I grabbed the fts sources from there and chucked them in this +directory along with a CMakeLists.txt that lets us build them with +CMake. + +What's the license? +=================== + +Being from NetBSD, it's the BSD license: + + Copyright (c) 1990, 1993, 1994 + The Regents of the University of California. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/swift-ci/sdks/static-linux/resources/fts/VERSION b/swift-ci/sdks/static-linux/resources/fts/VERSION new file mode 100644 index 00000000..c04c650a --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/VERSION @@ -0,0 +1 @@ +1.2.7 diff --git a/swift-ci/sdks/static-linux/resources/fts/config.h b/swift-ci/sdks/static-linux/resources/fts/config.h new file mode 100644 index 00000000..a9a53618 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/config.h @@ -0,0 +1,22 @@ +/* Configure definitions for Musl */ + +#ifndef FTS_CONFIG_H_ +#define FTS_CONFIG_H_ + +// We have dirfd(), in +#define HAVE_DIRFD 1 + +// MAX is defined in +#define HAVE_DECL_MAX 1 + +// UINTMAX_MAX is in +#define HAVE_DECL_UINTMAX_MAX 1 + +// We don't have d_namlen +//#undef HAVE_STRUCT_DIRENT_D_NAMLEN + +// DIR is opaque +//#undef HAVE_DIR_DD_FD +//#undef HAVE_DIR_D_FD + +#endif /* FTS_CONFIG_H_ */ diff --git a/swift-ci/sdks/static-linux/resources/fts/fts.3 b/swift-ci/sdks/static-linux/resources/fts/fts.3 new file mode 100644 index 00000000..9d7e0b7e --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/fts.3 @@ -0,0 +1,773 @@ +.\" $NetBSD: fts.3,v 1.30 2011/03/30 16:29:26 jruoho Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)fts.3 8.5 (Berkeley) 4/16/94 +.\" +.Dd March 30, 2011 +.Dt FTS 3 +.Os +.Sh NAME +.Nm fts , +.Nm fts_open , +.Nm fts_read , +.Nm fts_children , +.Nm fts_set , +.Nm fts_close +.Nd traverse a file hierarchy +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/types.h +.In sys/stat.h +.In fts.h +.Ft FTS * +.Fo fts_open +.Fa "char * const *path_argv" +.Fa "int options" +.Fa "int (*compar)(const FTSENT **, const FTSENT **)" +.Fc +.Ft FTSENT * +.Fn fts_read "FTS *ftsp" +.Ft FTSENT * +.Fn fts_children "FTS *ftsp" "int options" +.Ft int +.Fn fts_set "FTS *ftsp" "FTSENT *f" "int options" +.Ft int +.Fn fts_close "FTS *ftsp" +.Sh DESCRIPTION +The +.Nm +functions are provided for traversing +.Ux +file hierarchies. +A simple overview is that the +.Fn fts_open +function returns a +.Dq handle +on a file hierarchy, which is then supplied to +the other +.Nm +functions. +The function +.Fn fts_read +returns a pointer to a structure describing one of the files in the file +hierarchy. +The function +.Fn fts_children +returns a pointer to a linked list of structures, each of which describes +one of the files contained in a directory in the hierarchy. +In general, directories are visited two distinguishable times; in pre-order +(before any of their descendants are visited) and in post-order (after all +of their descendants have been visited). +Files are visited once. +It is possible to walk the hierarchy +.Dq logically +(ignoring symbolic links) +or physically (visiting symbolic links), order the walk of the hierarchy or +prune and/or re-visit portions of the hierarchy. +.Pp +Two structures are defined (and typedef'd) in the include file +.In fts.h . +The first is +.Fa FTS , +the structure that represents the file hierarchy itself. +The second is +.Fa FTSENT , +the structure that represents a file in the file +hierarchy. +Normally, an +.Fa FTSENT +structure is returned for every file in the file +hierarchy. +In this manual page, +.Dq file +and +.Dq Fa FTSENT No structure +are generally +interchangeable. +The +.Fa FTSENT +structure contains at least the following fields, which are +described in greater detail below: +.Bd -literal -offset 2n +typedef struct _ftsent { + u_short fts_info; /* flags for FTSENT structure */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + short fts_pathlen; /* strlen(fts_path) */ + char *fts_name; /* file name */ + short fts_namelen; /* strlen(fts_name) */ + short fts_level; /* depth (\-1 to N) */ + int fts_errno; /* file errno */ + long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + struct ftsent *fts_parent; /* parent directory */ + struct ftsent *fts_link; /* next file structure */ + struct ftsent *fts_cycle; /* cycle structure */ + struct stat *fts_statp; /* stat(2) information */ +} FTSENT; +.Ed +.Pp +These fields are defined as follows: +.Bl -tag -width "fts_namelen" +.It Fa fts_info +One of the following flags describing the returned +.Fa FTSENT +structure and +the file it represents. +With the exception of directories without errors +.Pq Dv FTS_D , +all of these +entries are terminal, that is, they will not be revisited, nor will any +of their descendants be visited. +.Bl -tag -width FTS_DEFAULT +.It Dv FTS_D +A directory being visited in pre-order. +.It Dv FTS_DC +A directory that causes a cycle in the tree. +(The +.Fa fts_cycle +field of the +.Fa FTSENT +structure will be filled in as well). +.It Dv FTS_DEFAULT +Any +.Fa FTSENT +structure that represents a file type not explicitly described +by one of the other +.Fa fts_info +values. +.It Dv FTS_DNR +A directory which cannot be read. +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_DOT +A file named +.Ql \&. +or +.Ql .. +which was not specified as a file name to +.Fn fts_open +(see +.Dv FTS_SEEDOT ) . +.It Dv FTS_DP +A directory being visited in post-order. +The contents of the +.Fa FTSENT +structure will be unchanged from when +it was returned in pre-order, i.e., with the +.Fa fts_info +field set to +.Dv FTS_D . +.It Dv FTS_ERR +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_F +A regular file. +.It Dv FTS_NS +A file for which no +.Xr stat 2 +information was available. +The contents of the +.Fa fts_statp +field are undefined. +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_NSOK +A file for which no +.Xr stat 2 +information was requested. +The contents of the +.Fa fts_statp +field are undefined. +.It Dv FTS_SL +A symbolic link. +.It Dv FTS_SLNONE +A symbolic link with a non-existent target. +The contents of the +.Fa fts_statp +field reference the file characteristic information for the symbolic link +itself. +.It Dv FTS_W +A whiteout object. +.El +.It Fa fts_accpath +A path for accessing the file from the current directory. +.It Fa fts_path +The path for the file relative to the root of the traversal. +This path contains the path specified to +.Fn fts_open +as a prefix. +.It Fa fts_pathlen +The length of the string referenced by +.Fa fts_path . +.It Fa fts_name +The name of the file. +.It Fa fts_namelen +The length of the string referenced by +.Fa fts_name . +.It Fa fts_level +The depth of the traversal, numbered from \-1 to N, where this file +was found. +The +.Fa FTSENT +structure representing the parent of the starting point (or root) +of the traversal is numbered \-1, and the +.Fa FTSENT +structure for the root +itself is numbered 0. +.It Fa fts_errno +Upon return of a +.Fa FTSENT +structure from the +.Fn fts_children +or +.Fn fts_read +functions, with its +.Fa fts_info +field set to +.Dv FTS_DNR , +.Dv FTS_ERR +or +.Dv FTS_NS , +the +.Fa fts_errno +field contains the value of the external variable +.Va errno +specifying the cause of the error. +Otherwise, the contents of the +.Fa fts_errno +field are undefined. +.It Fa fts_number +This field is provided for the use of the application program and is +not modified by the +.Nm +functions. +It is initialized to 0. +.It Fa fts_pointer +This field is provided for the use of the application program and is +not modified by the +.Nm +functions. +It is initialized to +.Dv NULL . +.It Fa fts_parent +A pointer to the +.Fa FTSENT +structure referencing the file in the hierarchy +immediately above the current file, i.e., the directory of which this +file is a member. +A parent structure for the initial entry point is provided as well, +however, only the +.Fa fts_level , +.Fa fts_number +and +.Fa fts_pointer +fields are guaranteed to be initialized. +.It Fa fts_link +Upon return from the +.Fn fts_children +function, the +.Fa fts_link +field points to the next structure in the +.Dv NULL Ns -terminated +linked list of directory members. +Otherwise, the contents of the +.Fa fts_link +field are undefined. +.It Fa fts_cycle +If a directory causes a cycle in the hierarchy (see +.Dv FTS_DC ) , +either because +of a hard link between two directories, or a symbolic link pointing to a +directory, the +.Fa fts_cycle +field of the structure will point to the +.Fa FTSENT +structure in the hierarchy that references the same file as the current +.Fa FTSENT +structure. +Otherwise, the contents of the +.Fa fts_cycle +field are undefined. +.It Fa fts_statp +A pointer to +.Xr stat 2 +information for the file. +.El +.Pp +A single buffer is used for all of the paths of all of the files in the +file hierarchy. +Therefore, the +.Fa fts_path +and +.Fa fts_accpath +fields are guaranteed to be +.Dv NULL Ns -terminated +.Em only +for the file most recently returned by +.Fn fts_read . +To use these fields to reference any files represented by other +.Fa FTSENT +structures will require that the path buffer be modified using the +information contained in that +.Fa FTSENT +structure's +.Fa fts_pathlen +field. +Any such modifications should be undone before further calls to +.Fn fts_read +are attempted. +The +.Fa fts_name +field is always +.Dv NULL Ns -terminated . +.Sh FTS_OPEN +The +.Fn fts_open +function takes a pointer to an array of character pointers naming one +or more paths which make up a logical file hierarchy to be traversed. +The array must be terminated by a +.Dv NULL +pointer. +.Pp +There are +a number of options, at least one of which (either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL ) +must be specified. +The options are selected by +.Em or Ns 'ing +the following values: +.Bl -tag -width "FTS_COMFOLLOW " +.It Dv FTS_COMFOLLOW +This option causes any symbolic link specified as a root path to be +followed immediately whether or not +.Dv FTS_LOGICAL +is also specified. +.It Dv FTS_LOGICAL +This option causes the +.Nm +routines to return +.Fa FTSENT +structures for the targets of symbolic links +instead of the symbolic links themselves. +If this option is set, the only symbolic links for which +.Fa FTSENT +structures +are returned to the application are those referencing non-existent files. +Either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL +.Em must +be provided to the +.Fn fts_open +function. +.It Dv FTS_NOCHDIR +As a performance optimization, the +.Nm +functions change directories as they walk the file hierarchy. +This has the side-effect that an application cannot rely on being +in any particular directory during the traversal. +The +.Dv FTS_NOCHDIR +option turns off this optimization, and the +.Nm +functions will not change the current directory. +Note that applications should not themselves change their current directory +and try to access files unless +.Dv FTS_NOCHDIR +is specified and absolute +pathnames were provided as arguments to +.Fn fts_open . +.It Dv FTS_NOSTAT +By default, returned +.Fa FTSENT +structures reference file characteristic information (the +.Fa statp +field) for each file visited. +This option relaxes that requirement as a performance optimization, +allowing the +.Nm +functions to set the +.Fa fts_info +field to +.Dv FTS_NSOK +and leave the contents of the +.Fa statp +field undefined. +.It Dv FTS_PHYSICAL +This option causes the +.Nm +routines to return +.Fa FTSENT +structures for symbolic links themselves instead +of the target files they point to. +If this option is set, +.Fa FTSENT +structures for all symbolic links in the +hierarchy are returned to the application. +Either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL +.Em must +be provided to the +.Fn fts_open +function. +.It Dv FTS_SEEDOT +By default, unless they are specified as path arguments to +.Fn fts_open , +any files named +.Ql \&. +or +.Ql .. +encountered in the file hierarchy are ignored. +This option causes the +.Nm +routines to return +.Fa FTSENT +structures for them. +.It Dv FTS_WHITEOUT +Return whiteout entries, which are normally hidden. +.It Dv FTS_XDEV +This option prevents +.Nm +from descending into directories that have a different device number +than the file from which the descent began. +.El +.Pp +The argument +.Fn compar +specifies a user-defined function which may be used to order the traversal +of the hierarchy. +It +takes two pointers to pointers to +.Fa FTSENT +structures as arguments and +should return a negative value, zero, or a positive value to indicate +if the file referenced by its first argument comes before, in any order +with respect to, or after, the file referenced by its second argument. +The +.Fa fts_accpath , +.Fa fts_path +and +.Fa fts_pathlen +fields of the +.Fa FTSENT +structures may +.Em never +be used in this comparison. +If the +.Fa fts_info +field is set to +.Dv FTS_NS +or +.Dv FTS_NSOK , +the +.Fa fts_statp +field may not either. +If the +.Fn compar +argument is +.Dv NULL , +the directory traversal order is in the order listed in +.Fa path_argv +for the root paths, and in the order listed in the directory for +everything else. +.Sh FTS_READ +The +.Fn fts_read +function returns a pointer to an +.Fa FTSENT +structure describing a file in +the hierarchy. +Directories (that are readable and do not cause cycles) are visited at +least twice, once in pre-order and once in post-order. +All other files are visited at least once. +(Hard links between directories that do not cause cycles or symbolic +links to symbolic links may cause files to be visited more than once, +or directories more than twice.) +.Pp +If all the members of the hierarchy have been returned, +.Fn fts_read +returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +If an error unrelated to a file in the hierarchy occurs, +.Fn fts_read +returns +.Dv NULL +and sets +.Va errno +appropriately. +If an error related to a returned file occurs, a pointer to an +.Fa FTSENT +structure is returned, and +.Va errno +may or may not have been set (see +.Fa fts_info ) . +.Pp +The +.Fa FTSENT +structures returned by +.Fn fts_read +may be overwritten after a call to +.Fn fts_close +on the same file hierarchy stream, or, after a call to +.Fn fts_read +on the same file hierarchy stream unless they represent a file of type +directory, in which case they will not be overwritten until after a call to +.Fn fts_read +after the +.Fa FTSENT +structure has been returned by the function +.Fn fts_read +in post-order. +.Sh FTS_CHILDREN +The +.Fn fts_children +function returns a pointer to an +.Fa FTSENT +structure describing the first entry in a +.Dv NULL Ns -terminated +linked list of the files in the directory represented by the +.Fa FTSENT +structure most recently returned by +.Fn fts_read . +The list is linked through the +.Fa fts_link +field of the +.Fa FTSENT +structure, and is ordered by the user-specified comparison function, if any. +Repeated calls to +.Fn fts_children +will recreate this linked list. +.Pp +As a special case, if +.Fn fts_read +has not yet been called for a hierarchy, +.Fn fts_children +will return a pointer to the files in the logical directory specified to +.Fn fts_open , +i.e., the arguments specified to +.Fn fts_open . +Otherwise, if the +.Fa FTSENT +structure most recently returned by +.Fn fts_read +is not a directory being visited in pre-order, +or the directory does not contain any files, +.Fn fts_children +returns +.Dv NULL +and sets +.Va errno +to zero. +If an error occurs, +.Fn fts_children +returns +.Dv NULL +and sets +.Va errno +appropriately. +.Pp +The +.Fa FTSENT +structures returned by +.Fn fts_children +may be overwritten after a call to +.Fn fts_children , +.Fn fts_close +or +.Fn fts_read +on the same file hierarchy stream. +.Pp +.Em Option +may be set to the following value: +.Bl -tag -width "FTS_COMFOLLOW " +.It Dv FTS_NAMEONLY +Only the names of the files are needed. +The contents of all the fields in the returned linked list of structures +are undefined with the exception of the +.Fa fts_name +and +.Fa fts_namelen +fields. +.El +.Sh FTS_SET +The function +.Fn fts_set +allows the user application to determine further processing for the +file +.Fa f +of the stream +.Fa ftsp . +The +.Fn fts_set +function +returns 0 on success, and \-1 if an error occurs. +.Em Option +must be set to one of the following values: +.Bl -tag -width "FTS_COMFOLLOW " +.It Dv FTS_AGAIN +Re-visit the file; any file type may be re-visited. +The next call to +.Fn fts_read +will return the referenced file. +The +.Fa fts_stat +and +.Fa fts_info +fields of the structure will be reinitialized at that time, +but no other fields will have been changed. +This option is meaningful only for the most recently returned +file from +.Fn fts_read . +Normal use is for post-order directory visits, where it causes the +directory to be re-visited (in both pre and post-order) as well as all +of its descendants. +.It Dv FTS_FOLLOW +The referenced file must be a symbolic link. +If the referenced file is the one most recently returned by +.Fn fts_read , +the next call to +.Fn fts_read +returns the file with the +.Fa fts_info +and +.Fa fts_statp +fields reinitialized to reflect the target of the symbolic link instead +of the symbolic link itself. +If the file is one of those most recently returned by +.Fn fts_children , +the +.Fa fts_info +and +.Fa fts_statp +fields of the structure, when returned by +.Fn fts_read , +will reflect the target of the symbolic link instead of the symbolic link +itself. +In either case, if the target of the symbolic link does not exist the +fields of the returned structure will be unchanged and the +.Fa fts_info +field will be set to +.Dv FTS_SLNONE . +.Pp +If the target of the link is a directory, the pre-order return, followed +by the return of all of its descendants, followed by a post-order return, +is done. +.It Dv FTS_SKIP +No descendants of this file are visited. +The file may be one of those most recently returned by either +.Fn fts_children +or +.Fn fts_read . +.El +.Sh FTS_CLOSE +The +.Fn fts_close +function closes a file hierarchy stream +.Fa ftsp +and restores the current directory to the directory from which +.Fn fts_open +was called to open +.Fa ftsp . +The +.Fn fts_close +function +returns 0 on success, and \-1 if an error occurs. +.Sh ERRORS +The function +.Fn fts_open +may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr open 2 +and +.Xr malloc 3 . +.Pp +The function +.Fn fts_close +may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr chdir 2 +and +.Xr close 2 . +.Pp +The functions +.Fn fts_read +and +.Fn fts_children +may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr chdir 2 , +.Xr malloc 3 , +.Xr opendir 3 , +.Xr readdir 3 +and +.Xr stat 2 . +.Pp +In addition, +.Fn fts_children , +.Fn fts_open +and +.Fn fts_set +may fail and set +.Va errno +as follows: +.Bl -tag -width Er +.It Bq Er EINVAL +The options were invalid. +.El +.Sh SEE ALSO +.Xr find 1 , +.Xr chdir 2 , +.Xr stat 2 , +.Xr qsort 3 , +.Xr symlink 7 +.Sh STANDARDS +The +.Nm +utility was expected to be included in the +.St -p1003.1-88 +revision. +But twenty years later, it still was not included in the +.St -p1003.1-2008 +revision. diff --git a/swift-ci/sdks/static-linux/resources/fts/fts.c b/swift-ci/sdks/static-linux/resources/fts/fts.c new file mode 100644 index 00000000..0f8d05bc --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/fts.c @@ -0,0 +1,1255 @@ +/* $NetBSD: fts.c,v 1.48 2015/01/29 15:55:21 manu Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +#else +__RCSID("$NetBSD: fts.c,v 1.48 2015/01/29 15:55:21 manu Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "config.h" + +#include +#include + +#include +#define _DIAGASSERT(e) +#include +#include +#include +#include +#include +#include +#include + +#if !defined(HAVE_DECL_MAX) || (HAVE_DECL_MAX==0) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#if !defined(UINT_MAX) && (HAVE_DECL_UINTMAX_MAX==1) +#define UINT_MAX UINTMAX_MAX +#endif + +#if !defined(HAVE_DIRFD) +#if defined(HAVE_DIR_DD_FD) +#define dirfd(dirp) ((dirp)->dd_fd) +#endif +#if defined(HAVE_DIR_D_FD) +#define dirfd(dirp) ((dirp)->d_fd) +#endif +#endif + +static FTSENT *fts_alloc(FTS *, const char *, size_t); +static FTSENT *fts_build(FTS *, int); +static void fts_free(FTSENT *); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static size_t fts_pow2(size_t); +static int fts_palloc(FTS *, size_t); +static void fts_padjust(FTS *, FTSENT *); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static unsigned short fts_stat(FTS *, FTSENT *, int); +static int fts_safe_changedir(const FTS *, const FTSENT *, int, + const char *); + +#if defined(ALIGNBYTES) && defined(ALIGN) +#define FTS_ALLOC_ALIGNED 1 +#else +#undef FTS_ALLOC_ALIGNED +#endif + +#ifndef ftsent_namelen_truncate +#define ftsent_namelen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef ftsent_pathlen_truncate +#define ftsent_pathlen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef fts_pathlen_truncate +#define fts_pathlen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef fts_nitems_truncate +#define fts_nitems_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +#ifndef DTF_HIDEW +#undef FTS_WHITEOUT +#endif + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + FTS *sp; + FTSENT *p, *root; + size_t nitems; + FTSENT *parent, *tmp = NULL; /* pacify gcc */ + size_t len; + + _DIAGASSERT(argv != NULL); + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = malloc(sizeof(FTS))) == NULL) + return (NULL); + memset(sp, 0, sizeof(FTS)); + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + if ((p = fts_alloc(sp, *argv, len)) == NULL) + goto mem3; + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + if (!ISSET(FTS_NOCHDIR)) { + if ((sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) + SET(FTS_NOCHDIR); + } + + if (nitems == 0) + fts_free(parent); + + return (sp); + +mem3: fts_lfree(root); + fts_free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = ftsent_namelen_truncate(len); + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + int saved_errno = 0; + + _DIAGASSERT(sp != NULL); + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + if (sp->fts_cur->fts_flags & FTS_SYMFOLLOW) + (void)close(sp->fts_cur->fts_symfd); + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + fts_free(freep); + } + fts_free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + if (fchdir(sp->fts_rfd) == -1) + saved_errno = errno; + (void)close(sp->fts_rfd); + } + + /* Free up the stream pointer. */ + free(sp); + if (saved_errno) { + errno = saved_errno; + return -1; + } + + return 0; +} + +#if !defined(__FTS_COMPAT_TAILINGSLASH) + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +#else /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +/* + * compatibility with the old behaviour. + * + * Special case a root of "/" so that slashes aren't appended which would + * cause paths to be written as "//foo". + */ + +#define NAPPEND(p) \ + (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ + p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + +#endif /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + _DIAGASSERT(sp != NULL); + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC, 0)) + == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p; p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + +next: + /* Move to the next node on this level. */ + tmp = p; + + /* + * We are going to free sp->fts_cur, set it to NULL so + * that fts_close() does not attempt to free it again + * if we exit without setting it to a new value because + * FCHDIR() failed below. + */ + assert(tmp == sp->fts_cur); + sp->fts_cur = NULL; + + if ((p = p->fts_link) != NULL) { + fts_free(tmp); + + /* + * If reached the top, return to the original directory, and + * load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1)); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + fts_free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + fts_free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + _DIAGASSERT(sp != NULL); + + if (instr && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) + return (sp->fts_child = NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void)close(fd); + return (NULL); + } + (void)close(fd); + return (sp->fts_child); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct dirent *dp; + FTSENT *p, *head; + size_t nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t dnamlen; + int cderrno, descend, level, nlinks, saved_errno, nostat, doadjust; + size_t len, maxlen; +#ifdef FTS_WHITEOUT + int oflag; +#endif + char *cp = NULL; /* pacify gcc */ + + _DIAGASSERT(sp != NULL); + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP|DTF_REWIND; + else + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + nostat = 1; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } + len++; + maxlen = sp->fts_pathlen - len; + +#if defined(__FTS_COMPAT_LEVEL) + if (cur->fts_level == SHRT_MAX) { + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) { + + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + +#if defined(HAVE_STRUCT_DIRENT_D_NAMLEN) + dnamlen = dp->d_namlen; +#else + dnamlen = strlen(dp->d_name); +#endif + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + errno = saved_errno; + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + +#if defined(__FTS_COMPAT_LENGTH) + if (len + dnamlen >= USHRT_MAX) { + /* + * In an FTSENT, fts_pathlen is an unsigned short + * so it is possible to wraparound here. + * If we do, free up the current structure and the + * structures already allocated, then error out + * with ENAMETOOLONG. + */ + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + p->fts_level = level; + p->fts_pathlen = ftsent_pathlen_truncate(len + dnamlen); + p->fts_parent = sp->fts_cur; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, + (size_t)(p->fts_namelen + 1)); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + (void)closedir(dirp); + + /* + * If had to realloc the path, adjust the addresses for the rest + * of the tree. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static unsigned short +fts_stat(FTS *sp, FTSENT *p, int follow) +{ + FTSENT *t; + dev_t dev; + __fts_ino_t ino; + __fts_stat_t *sbp, sb; + int saved_errno; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* check for whiteout */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof (*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!lstat(p->fts_accpath, sbp)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, size_t nitems) +{ + FTSENT **ap, *p; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(head != NULL); + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + FTSENT **new; + + new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40)); + if (new == 0) + return (head); + sp->fts_array = new; + sp->fts_nitems = fts_nitems_truncate(nitems + 40); + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), + (int (*)(const void *, const void *))sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, const char *name, size_t namelen) +{ + FTSENT *p; +#if defined(FTS_ALLOC_ALIGNED) + size_t len; +#endif + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(name != NULL); + +#if defined(FTS_ALLOC_ALIGNED) + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(*(p->fts_statp)) + ALIGNBYTES; + if ((p = malloc(len)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (__fts_stat_t *)ALIGN( + (unsigned long)(p->fts_name + namelen + 2)); +#else + if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + if ((p->fts_statp = malloc(sizeof(*(p->fts_statp)))) == NULL) { + free(p); + return (NULL); + } +#endif + + if (ISSET(FTS_NOSTAT)) + p->fts_statp = NULL; + + /* Copy the name plus the trailing NULL. */ + memmove(p->fts_name, name, namelen + 1); + + p->fts_namelen = ftsent_namelen_truncate(namelen); + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + return (p); +} + +static void +fts_free(FTSENT *p) +{ +#if !defined(FTS_ALLOC_ALIGNED) + if (p->fts_statp) + free(p->fts_statp); +#endif + free(p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* XXX: head may be NULL ? */ + + /* Free a linked list of structures. */ + while ((p = head) != NULL) { + head = head->fts_link; + fts_free(p); + } +} + +static size_t +fts_pow2(size_t x) +{ + + x--; + x |= x>>1; + x |= x>>2; + x |= x>>4; + x |= x>>8; + x |= x>>16; +#if LONG_BIT > 32 + x |= x>>32; +#endif +#if LONG_BIT > 64 + x |= x>>64; +#endif + x++; + return (x); +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Round up the new size to a power of 2, + * so we don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t size) +{ + char *new; + + _DIAGASSERT(sp != NULL); + +#ifdef __FTS_COMPAT_LENGTH + /* Protect against fts_pathlen overflow. */ + if (size > USHRT_MAX + 1) { + errno = ENAMETOOLONG; + return (1); + } +#endif + size = fts_pow2(size); + new = realloc(sp->fts_path, size); + if (new == 0) + return (1); + sp->fts_path = new; + sp->fts_pathlen = fts_pathlen_truncate(size); + return (0); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr; + + _DIAGASSERT(sp != NULL); + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) \ + (p)->fts_accpath = \ + addr + ((p)->fts_accpath - (p)->fts_path); \ + (p)->fts_path = addr; \ +} while (/*CONSTCOND*/0) + + addr = sp->fts_path; + + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + _DIAGASSERT(argv != NULL); + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(const FTS *sp, const FTSENT *p, int fd, const char *path) +{ + int oldfd = fd, ret = -1; + __fts_stat_t sb; + + if (ISSET(FTS_NOCHDIR)) + return 0; + + if (oldfd < 0 && (fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) + return -1; + + if (fstat(fd, &sb) == -1) + goto bail; + + if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) { + errno = ENOENT; + goto bail; + } + + ret = fchdir(fd); + +bail: + if (oldfd < 0) { + int save_errno = errno; + (void)close(fd); + errno = save_errno; + } + return ret; +} diff --git a/swift-ci/sdks/static-linux/resources/fts/fts.h b/swift-ci/sdks/static-linux/resources/fts/fts.h new file mode 100644 index 00000000..3cd4b62d --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/fts/fts.h @@ -0,0 +1,157 @@ +/* $NetBSD: fts.h,v 1.19 2009/08/16 19:33:38 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + */ + +#ifndef _FTS_H_ +#define _FTS_H_ + +#include +#include +#include +#include + +#ifndef __fts_stat_t +#define __fts_stat_t struct stat +#endif +#ifndef __fts_nlink_t +#define __fts_nlink_t nlink_t +#endif +#ifndef __fts_ino_t +#define __fts_ino_t ino_t +#endif +#ifndef __fts_length_t +#define __fts_length_t unsigned int +#endif +#ifndef __fts_number_t +#define __fts_number_t int64_t +#endif +#ifndef __fts_dev_t +#define __fts_dev_t dev_t +#endif +#ifndef __fts_level_t +#define __fts_level_t int +#endif + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + unsigned int fts_pathlen; /* sizeof(path) */ + unsigned int fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent **, const struct _ftsent **); + +#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x002 /* logical walk */ +#define FTS_NOCHDIR 0x004 /* don't change directories */ +#define FTS_NOSTAT 0x008 /* don't get stat info */ +#define FTS_PHYSICAL 0x010 /* physical walk */ +#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ +#define FTS_XDEV 0x040 /* don't cross devices */ +#define FTS_WHITEOUT 0x080 /* return whiteout information */ +#define FTS_OPTIONMASK 0x0ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x100 /* (private) child names only */ +#define FTS_STOP 0x200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + __fts_number_t fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + __fts_length_t fts_pathlen; /* strlen(fts_path) */ + __fts_length_t fts_namelen; /* strlen(fts_name) */ + + __fts_ino_t fts_ino; /* inode */ + __fts_dev_t fts_dev; /* device */ + __fts_nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + __fts_level_t fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + unsigned short fts_info; /* user flags for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ +#define FTS_ISW 0x04 /* this is a whiteout object */ + unsigned short fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + unsigned short fts_instr; /* fts_set() instructions */ + + __fts_stat_t *fts_statp; /* stat(2) information */ + char fts_name[1]; /* file name */ +} FTSENT; + +#ifdef __cplusplus +extern "C" { +#endif +FTSENT *fts_children(FTS *, int); +int fts_close(FTS *); +FTS *fts_open(char * const *, int, + int (*)(const FTSENT **, const FTSENT **)); +FTSENT *fts_read(FTS *); +int fts_set(FTS *, FTSENT *, int); +#ifdef __cplusplus +} +#endif + + +#endif /* !_FTS_H_ */ diff --git a/swift-ci/sdks/static-linux/resources/linux/capability.h b/swift-ci/sdks/static-linux/resources/linux/capability.h new file mode 100644 index 00000000..98668ba8 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/capability.h @@ -0,0 +1,59 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This just contains the #define values for the capabilities and nothing else. */ + +#ifndef _LINUX_CAPABILITY_H +#define _LINUX_CAPABILITY_H + +#define CAP_CHOWN 0 +#define CAP_DAC_OVERRIDE 1 +#define CAP_DAC_READ_SEARCH 2 +#define CAP_FOWNER 3 +#define CAP_FSETID 4 +#define CAP_KILL 5 +#define CAP_SETGID 6 +#define CAP_SETUID 7 +#define CAP_SETPCAP 8 +#define CAP_LINUX_IMMUTABLE 9 +#define CAP_NET_BIND_SERVICE 10 +#define CAP_NET_BROADCAST 11 +#define CAP_NET_ADMIN 12 +#define CAP_NET_RAW 13 +#define CAP_IPC_LOCK 14 +#define CAP_IPC_OWNER 15 +#define CAP_SYS_MODULE 16 +#define CAP_SYS_RAWIO 17 +#define CAP_SYS_CHROOT 18 +#define CAP_SYS_PTRACE 19 +#define CAP_SYS_PACCT 20 +#define CAP_SYS_ADMIN 21 +#define CAP_SYS_BOOT 22 +#define CAP_SYS_NICE 23 +#define CAP_SYS_RESOURCE 24 +#define CAP_SYS_TIME 25 +#define CAP_SYS_TTY_CONFIG 26 +#define CAP_MKNOD 27 +#define CAP_LEASE 28 +#define CAP_AUDIT_WRITE 29 +#define CAP_AUDIT_CONTROL 30 +#define CAP_SETFCAP 31 +#define CAP_MAC_OVERRIDE 32 +#define CAP_MAC_ADMIN 33 +#define CAP_SYSLOG 34 +#define CAP_WAKE_ALARM 35 +#define CAP_BLOCK_SUSPEND 36 +#define CAP_AUDIT_READ 37 + +#endif /* _LINUX_CAPABILITY_H */ diff --git a/swift-ci/sdks/static-linux/resources/linux/futex.h b/swift-ci/sdks/static-linux/resources/linux/futex.h new file mode 100644 index 00000000..fe2d6a03 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/futex.h @@ -0,0 +1,71 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This just contains the #define values we need to use futexes, and + nothing else. */ + +#ifndef _LINUX_FUTEX_H +#define _LINUX_FUTEX_H + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 +#define FUTEX_WAKE_BITSET 10 +#define FUTEX_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 + +#define FUTEX_PRIVATE_FLAG 128 +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) + +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | FUTEX_PRIVATE_FLAG) + +#define FUTEX_TID_MASK 0x3fffffff +#define FUTEX_OWNER_DIED 0x40000000 +#define FUTEX_WAITERS 0x80000000 + +#define FUTEX_OP_SET 0 +#define FUTEX_OP_ADD 1 +#define FUTEX_OP_OR 2 +#define FUTEX_OP_ANDN 3 +#define FUTEX_OP_XOR 4 + +#define FUTEX_OP_OPARG_SHIFT 8 + +#define FUTEX_OP_CMP_EQ 0 +#define FUTEX_OP_CMP_NE 1 +#define FUTEX_OP_CMP_LT 2 +#define FUTEX_OP_CMP_LE 3 +#define FUTEX_OP_CMP_GT 4 +#define FUTEX_OP_CMP_GE 5 + +#endif /* _LINUX_FUTEX_H */ diff --git a/swift-ci/sdks/static-linux/resources/linux/limits.h b/swift-ci/sdks/static-linux/resources/linux/limits.h new file mode 100644 index 00000000..3e782ace --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/limits.h @@ -0,0 +1,22 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This just includes so we can pick up PATH_MAX from Musl's header. */ + +#ifndef _LINUX_LIMITS_H +#define _LINUX_LIMITS_H + +#include + +#endif /* _LINUX_LIMITS_H */ diff --git a/swift-ci/sdks/static-linux/resources/linux/random.h b/swift-ci/sdks/static-linux/resources/linux/random.h new file mode 100644 index 00000000..ebdba105 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/random.h @@ -0,0 +1,30 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This just contains constants needed to build BoringSSL */ + +#ifndef _LINUX_RANDOM_H +#define _LINUX_RANDOM_H + +#include + +#define RNDGETENTCNT 0x80045200 +#define RNDADDTOENTCNT 0x40045201 +#define RNDGETPOOL 0x80085202 +#define RNDADDENTROPY 0x40085203 +#define RNDZAPENTCNT 0x5204 +#define RNDCLEARPOOL 0x5206 +#define RNDRESEEDCRNG 0x5207 + +#endif /* _LINUX_RANDOM_H */ diff --git a/swift-ci/sdks/static-linux/resources/linux/sockios.h b/swift-ci/sdks/static-linux/resources/linux/sockios.h new file mode 100644 index 00000000..0b8b54cf --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/sockios.h @@ -0,0 +1,24 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This contains a couple of SIOC constants that aren't included in + Musl's but that we need for libdispatch. */ + +#ifndef _LINUX_SOCKIOS_H +#define _LINUX_SOCKIOS_H + +#define SIOCINQ 0x541B +#define SIOCOUTQ 0x5411 + +#endif /* _LINUX_SOCKIOS_H */ diff --git a/swift-ci/sdks/static-linux/resources/linux/vm_sockets.h b/swift-ci/sdks/static-linux/resources/linux/vm_sockets.h new file mode 100644 index 00000000..d62c3347 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/linux/vm_sockets.h @@ -0,0 +1,49 @@ +/* ===----------------------------------------------------------------------=== + + Swift Static SDK for Linux: Header Shim + + This source file is part of the Swift.org open source project + + Copyright (c) 2024 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + ===----------------------------------------------------------------------=== */ + +/* This contains some VMWare vSockets constants and structs that are needed by + Swift NIO. */ + +#ifndef _LINUX_VM_SOCKETS_H +#define _LINUX_VM_SOCKETS_H + +// The official one doesn't actually include this, but probably should +#include + +#define SO_VM_SOCKETS_NONBLOCK_TXRX 7 + +#define VMADDR_CID_ANY -1U +#define VMADDR_PORT_ANY -1U + +#define VMADDR_CID_HYPERVISOR 0 +#define VMADDR_CID_LOCAL 1 +#define VMADDR_CID_HOST 2 + +#define VM_SOCKETS_INVALID_VERSION -1U + +#define IOCTL_VM_SOCKETS_GET_LOCAL_CID 0x07b9 + +struct sockaddr_vm { + sa_family_t svm_family; + unsigned short svm_reserved1; + unsigned int svm_port; + unsigned int svm_cid; + unsigned char svm_zero[sizeof(struct sockaddr) + - sizeof(sa_family_t) + - sizeof(unsigned short) + - sizeof(unsigned int) + - sizeof(unsigned int)]; +}; + +#endif /* _LINUX_VM_SOCKETS_H */ diff --git a/swift-ci/sdks/static-linux/resources/patches/musl.patch b/swift-ci/sdks/static-linux/resources/patches/musl.patch new file mode 100644 index 00000000..34fe4e90 --- /dev/null +++ b/swift-ci/sdks/static-linux/resources/patches/musl.patch @@ -0,0 +1,73 @@ +diff --git a/src/locale/locale_map.c b/src/locale/locale_map.c +index da61f7fc..097da1ad 100644 +--- a/src/locale/locale_map.c ++++ b/src/locale/locale_map.c +@@ -31,7 +31,7 @@ static const char envvars[][12] = { + volatile int __locale_lock[1]; + volatile int *const __locale_lockptr = __locale_lock; + +-const struct __locale_map *__get_locale(int cat, const char *val) ++const struct __locale_map *__get_locale(int cat, const char *locale) + { + static void *volatile loc_head; + const struct __locale_map *p; +@@ -39,6 +39,7 @@ const struct __locale_map *__get_locale(int cat, const char *val) + const char *path = 0, *z; + char buf[256]; + size_t l, n; ++ const char *val = locale; + + if (!*val) { + (val = getenv("LC_ALL")) && *val || +@@ -92,22 +93,18 @@ const struct __locale_map *__get_locale(int cat, const char *val) + } + } + +- /* If no locale definition was found, make a locale map +- * object anyway to store the name, which is kept for the +- * sake of being able to do message translations at the +- * application level. */ +- if (!new && (new = malloc(sizeof *new))) { +- new->map = __c_dot_utf8.map; +- new->map_size = __c_dot_utf8.map_size; +- memcpy(new->name, val, n); +- new->name[n] = 0; +- new->next = loc_head; +- loc_head = new; +- } ++ /* If no locale definition was found, and we specified a ++ * locale name of "", return the C.UTF-8 locale. */ ++ if (!new && !*locale) new = (void *)&__c_dot_utf8; + + /* For LC_CTYPE, never return a null pointer unless the + * requested name was "C" or "POSIX". */ + if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8; + ++ /* Returning NULL means "C locale"; if we get here and ++ * there's no locale, return failure instead. */ ++ if (!new) ++ return LOC_MAP_FAILED; ++ + return new; + } +diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c +index 360c4437..9842d95d 100644 +--- a/src/locale/setlocale.c ++++ b/src/locale/setlocale.c +@@ -28,12 +28,14 @@ char *setlocale(int cat, const char *name) + const char *p = name; + for (i=0; i LOCALE_NAME_MAX) ++ lm = LOC_MAP_FAILED; ++ else { + memcpy(part, p, z-p); + part[z-p] = 0; + if (*z) p = z+1; ++ lm = __get_locale(i, part); + } +- lm = __get_locale(i, part); + if (lm == LOC_MAP_FAILED) { + UNLOCK(__locale_lock); + return 0; diff --git a/swift-ci/sdks/static-linux/scripts/build.sh b/swift-ci/sdks/static-linux/scripts/build.sh new file mode 100755 index 00000000..1a4e9b87 --- /dev/null +++ b/swift-ci/sdks/static-linux/scripts/build.sh @@ -0,0 +1,910 @@ +#!/bin/bash +# +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Build Script +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +set -e + +# Docker sets TERM to xterm if using a pty; we probably want +# xterm-256color, otherwise we only get eight colors +if [ -t 1 ]; then + if [[ "$TERM" == "xterm" ]]; then + export TERM=xterm-256color + fi +fi + +bold=$(tput bold) +white=$(tput setaf 15) +grey=$(tput setaf 8) +reset=$(tput sgr0) + +function cleanup { + echo "${reset}" +} +trap cleanup EXIT + +function header { + local text="$1" + echo "" + echo "${white}${bold}*** ${text} ***${reset}${grey}" + echo "" +} + +function usage { + cat < --products-dir + [--name ] [--version ] [--build-dir ] + [--archs [, ...]] + +Build the fully statically linked SDK for Linux. + +Options: + + --name Specify the name of the SDK bundle. + --version Specify the version of the Static Linux SDK. + --source-dir Specify the path in which the sources can be found. + --products-dir Specify the path in which the products should be written. + --build-dir Specify the path in which intermediates should be stored. + --archs [, ...] + Specify the architectures for which we should build + the SDK. + (Default is ${archs}). + --build Specify the CMake build type to use (Release, Debug, + RelWithDebInfo). + (Default is ${build_type}). + -j + --jobs Specify the number of parallel jobs to run at a time. + (Default is ${parallel_jobs}.) +EOF +} + +# Declare all the packages we depend on +declare -a packages + +function declare_package +{ + local name=$1 + local userVisibleName=$2 + local license=$3 + local url=$4 + + local snake=$(echo ${name} | tr '_' '-') + + declare -g ${name}_snake="$snake" + declare -g ${name}_name="$userVisibleName" + declare -g ${name}_license="$license" + declare -g ${name}_url="$url" + + packages+=(${name}) +} + +declare_package static_linux_sdk \ + "Swift statically linked SDK for Linux" \ + "Apache-2.0" "https://swift.org/install/sdk" +declare_package swift "swift" "Apache-2.0" "https://swift.org" +declare_package musl "musl" "MIT" "https://musl.org" +declare_package musl_fts "musl-fts" "BSD-3-Clause" \ + "https://github.com/void-linux/musl-fts" +declare_package libxml2 "libxml2" "MIT" \ + "https://github.com/GNOME/libxml2" +declare_package curl "curl" "MIT" "https://curl.se" +declare_package boringssl "boringssl" "OpenSSL AND ISC AND MIT" \ + "https://boringssl.googlesource.com/boringssl/" +declare_package icu "icu" \ + "Unicode-3.0 AND ICU AND BSD-3-Clause AND NAIST-2003 AND MIT" \ + "https://icu.unicode.org" +declare_package zlib "zlib" "Zlib" "https://zlib.net" + +# Parse command line arguments +static_linux_sdk_version=0.0.1 +sdk_name= +archs=x86_64,aarch64 +build_type=RelWithDebInfo +parallel_jobs=$(($(nproc --all) + 2)) +source_dir= +build_dir=$(pwd)/build +products_dir= +while [ "$#" -gt 0 ]; do + case "$1" in + --source-dir) + source_dir="$2"; shift ;; + --build-dir) + build_dir="$2"; shift ;; + --products-dir) + products_dir="$2"; shift ;; + --name) + sdk_name="$2"; shift ;; + --archs) + archs="$2"; shift ;; + --version) + static_linux_sdk_version="$2"; shift ;; + *) + usage; exit 0 ;; + esac + shift +done + +# Change the commas for spaces +archs="${archs//,/ }" + +if [[ -z "$source_dir" || -z "$products_dir" ]]; then + usage + exit 1 +fi + +if ! swiftc=$(which swiftc); then + echo "build.sh: Unable to find Swift compiler. You must have a Swift toolchain installed to build the statically linked SDK." + exit 1 +fi + +script_dir=$(dirname -- "${BASH_SOURCE[0]}") +resource_dir="${script_dir}/../resources" + +# Find the version numbers of the various dependencies +function describe { + pushd $1 >/dev/null 2>&1 + git describe --tags + popd >/dev/null 2>&1 +} +function versionFromTag { + desc=$(describe $1) + if [[ $desc == v* ]]; then + echo "${desc#v}" + else + echo "${desc}" + fi +} + +swift_version=$(describe ${source_dir}/swift-project/swift) +if [[ $swift_version == swift-* ]]; then + swift_version=${swift_version#swift-} +fi + +if [[ -z "$sdk_name" ]]; then + sdk_name=swift-${swift_version}_static-linux-${static_linux_sdk_version} +fi + +musl_version=$(versionFromTag ${source_dir}/musl) + +musl_fts_version=$(cat ${resource_dir}/fts/VERSION) + +libxml2_version=$(versionFromTag ${source_dir}/libxml2) + +curl_desc=$(describe ${source_dir}/curl | tr '_' '.') +curl_version=${curl_desc#curl-} + +boringssl_version=$(describe ${source_dir}/boringssl) + +icu_version=$(describe ${source_dir}/icu) + +zlib_version=$(versionFromTag ${source_dir}/zlib) + +function quiet_pushd { + pushd "$1" >/dev/null 2>&1 +} +function quiet_popd { + popd >/dev/null 2>&1 +} + +header "Fully statically linked Linux SDK build script" + +swift_dir=$(realpath $(dirname "$swiftc")/..) + +echo "Swift found at ${swift_dir}" +echo "Building for ${archs}" +echo "Sources are in ${source_dir}" +echo "Build will happen in ${build_dir}" +echo "Products will be placed in ${products_dir}" +echo +echo "Building from:" +echo " - Swift ${swift_version}" +echo " - Musl ${musl_version}" +echo " - Musl FTS ${musl_fts_version}" +echo " - libxml2 ${libxml2_version}" +echo " - curl ${curl_version}" +echo " - BoringSSL ${boringssl_version}" +echo " - ICU ${icu_version}" +echo " - zlib ${zlib_version}" + +function run() { + echo "$@" + "$@" +} + +header "Patching Musl" + +echo -n "Patching Musl for locale support... " +patch=$(realpath "${resource_dir}/patches/musl.patch") +if git -C ${source_dir}/musl apply --reverse --check "$patch" >/dev/null 2>&1; then + echo "already patched" +elif git -C ${source_dir}/musl apply "$patch" >/dev/null 2>&1; then + echo "done" +else + echo "failed" + exit 1 +fi + +header "Building ICU for host system" + +mkdir -p ${build_dir}/icu +quiet_pushd ${build_dir}/icu +run "${source_dir}/icu/icu4c/source/configure" +run make -j$parallel_jobs +quiet_popd + +for arch in $archs; do + + # Fix architecture names + alt_arch=$arch + case $arch in + amd64) arch=x86_64 ;; + aarch64|arm64) arch=aarch64; alt_arch=arm64 ;; + esac + + triple=${arch}-swift-linux-musl + + sdk_root=${build_dir}/sdk_root/${arch} + mkdir -p "$sdk_root" + + sdk_resource_dir="${sdk_root}/usr/lib/swift/clang" + mkdir -p "${sdk_resource_dir}/include" \ + "${sdk_resource_dir}/lib/linux" \ + "${sdk_root}/usr/lib/swift_static" + ln -sf ../swift/clang "${sdk_root}/usr/lib/swift_static/clang" + + clang_resource_dir=$(${swift_dir}/bin/clang -print-resource-dir) + cp -rT $clang_resource_dir/include $sdk_resource_dir/include + + cc="${swift_dir}/bin/clang -target $triple -resource-dir ${sdk_resource_dir} --sysroot ${sdk_root}" + cxx="${swift_dir}/bin/clang++ -target $triple -resource-dir ${sdk_resource_dir} --sysroot ${sdk_root}" + as="$cc" + + # Creating this gets rid of a warning + cat > $sdk_root/SDKSettings.json <:g;/#include /d" $header + done + mkdir _modules + for header in assert complex ctype errno fenv float inttypes iso646 \ + limits locale math setjmp stdalign stdarg stdatomic \ + stdbool stddef stdint stdio stdlib string tgmath \ + uchar wchar wctype; do + echo "Making _modules/${header}_h.h" + cat > _modules/${header}_h.h < instead" +#endif +#include <${header}.h> +EOF + done + quiet_popd + + # ----------------------------------------------------------------------- + + header "Constructing modulemap" + + # Install the modulemap but *not* SwiftMusl.h + awk ' +/^\/\/ START SWIFT ONLY/ { ignore=1 } +/^\/\/ END SWIFT ONLY/ { ignore=0; next } +ignore == 0 { print } +' \ + "${source_dir}/swift-project/swift/stdlib/public/Platform/musl.modulemap" \ + > "$sdk_root/usr/include/module.modulemap" + echo "OK" + + # ----------------------------------------------------------------------- + + header "Setting up for build" + + # Not having these makes CMake compiler identification fail, because + # it can't compile a C++ program, so make dummy files for now. + touch ${sdk_root}/usr/lib/libc++.a + touch ${sdk_root}/usr/lib/libc++abi.a + touch ${sdk_root}/usr/lib/libunwind.a + touch ${sdk_resource_dir}/lib/linux/libclang_rt.builtins-${arch}.a + touch ${sdk_resource_dir}/lib/linux/crtbeginT.o + touch ${sdk_resource_dir}/lib/linux/crtend.o + + # Install a couple of fake Linux kernel headers; we don't want to + # use the actual kernel headers because they're GPL'd. + mkdir -p ${sdk_root}/usr/include + cp -r ${resource_dir}/linux ${sdk_root}/usr/include + + # Create a CMake toolchain file + cat > ${build_dir}/${arch}/toolchain.cmake <> $llvm_bin/${arch}-swift-linux-musl-clang.cfg <> build/$arch/toolchain.cmake < "$linkfile" + + # ----------------------------------------------------------------------- + + header "Building Dispatch for $arch" + + run cmake -G Ninja -S ${source_dir}/swift-project/swift-corelibs-libdispatch \ + -B ${build_dir}/$arch/dispatch \ + -DCMAKE_TOOLCHAIN_FILE=${build_dir}/$arch/toolchain.cmake \ + -DCMAKE_REQUIRED_DEFINITIONS=-D_GNU_SOURCE \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX=$sdk_root/usr \ + -DBUILD_SHARED_LIBS=NO \ + -DENABLE_SWIFT=YES \ + -DSWIFT_SYSTEM_NAME=linux-static + + quiet_pushd ${build_dir}/$arch/dispatch + run ninja -j$parallel_jobs + quiet_popd + + # ----------------------------------------------------------------------- + + header "Building Foundation for $arch" + + run cmake -G Ninja -S ${source_dir}/swift-project/swift-corelibs-foundation \ + -B ${build_dir}/$arch/foundation \ + -DCMAKE_TOOLCHAIN_FILE=${build_dir}/$arch/toolchain.cmake \ + -DCMAKE_REQUIRED_DEFINITIONS=-D_GNU_SOURCE \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX=$sdk_root/usr \ + -DCMAKE_INSTALL_LIBDIR=lib/swift_static/linux-static \ + -DBUILD_SHARED_LIBS=NO \ + -DBUILD_FULLY_STATIC=YES \ + -DSWIFT_SYSTEM_NAME=linux-static \ + -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=${source_dir}/swift-project/swift-corelibs-libdispatch \ + -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=${build_dir}/$arch/dispatch \ + -Ddispatch_DIR=${build_dir}/$arch/dispatch/cmake/modules + + quiet_pushd ${build_dir}/$arch/foundation + run ninja -j$parallel_jobs + quiet_popd + + # ----------------------------------------------------------------------- + + # Install Foundation *before* Dispatch because the former doesn't expect + # to find Dispatch installed :-( + + quiet_pushd ${build_dir}/$arch/foundation + run ninja -j$parallel_jobs install + quiet_popd + + # ----------------------------------------------------------------------- + + # Install Dispatch *after* building Foundation, because the latter doesn't + # expect it to be installed when Foundation is building. + + quiet_pushd ${build_dir}/$arch/dispatch + run ninja -j$parallel_jobs install + quiet_popd + + # Finally, put the static-stdlib-args.lnk file back + mv -f "$linkfile.bak" "$linkfile" + + # ----------------------------------------------------------------------- + + # We don't need the Linux libraries here, but turning off the Linux build + # causes trouble, so we're going to end up building them anyway. + rm -rf \ + $sdk_root/usr/lib/swift/linux \ + $sdk_root/usr/lib/swift_static/linux + +done + +# Now generate the bundle +header "Bundling SDK" + +spdx_uuid=$(uuidgen) +spdx_doc_uuid=$(uuidgen) +spdx_timestamp=$(date -Iseconds) + +sdk_name=swift-${swift_version}_static-linux-${static_linux_sdk_version} +bundle="${sdk_name}.artifactbundle" + +rm -rf "${build_dir}/$bundle" +mkdir -p "${build_dir}/$bundle/$sdk_name/swift-linux-musl" + +quiet_pushd ${build_dir}/$bundle + +# First the info.json, for SwiftPM +cat > info.json < sbom.spdx.json <> sbom.spdx.json <> sbom.spdx.json <> sbom.spdx.json <> sbom.spdx.json <> sbom.spdx.json <> sbom.spdx.json < swift-sdk.json <> swift-sdk.json <> swift-sdk.json <> swift-sdk.json < toolset.json <|--swift-tag + |--swift-version ] + [--musl-version ] [--libxml2-version ] + [--curl-version ] + [--boringssl-version ] + [--icu-version ] [--zlib-version ] + [--clone-with-ssh] + [--source-dir ] + +Fetch all the sources required to build the fully statically linked Linux +SDK for Swift. Options are: + + --clone-with-ssh Use git-over-SSH rather than HTTPS where possible. + --source-dir Specify the path in which the sources should be checked + out. This directory will be created it if does not exist. + --swift-scheme + --swift-tag + --swift-version + Select the version of Swift to check out sources for. + If starts with "scheme:" or "tag:", it will + select a scheme or tag; otherwise it will be treated as + a version number. + --musl-version + --libxml2-version + --curl-version + --boringssl-version + --icu-version + --zlib-version + Select the versions of other dependencies. +EOF +} + +# Defaults +if [[ -z "${SWIFT_VERSION}" ]]; then + SWIFT_VERSION=scheme:release/6.0 +fi +if [[ -z "${MUSL_VERSION}" ]]; then + MUSL_VERSION=1.2.5 +fi +if [[ -z "${LIBXML2_VERSION}" ]]; then + LIBXML2_VERSION=2.12.7 +fi +if [[ -z "${CURL_VERSION}" ]]; then + CURL_VERSION=8.7.1 +fi +if [[ -z "${BORINGSSL_VERSION}" ]]; then + BORINGSSL_VERSION=fips-20220613 +fi +if [[ -z "${ICU_VERSION}" ]]; then + ICU_VERSION=maint/maint-69 +fi +if [[ -z "${ZLIB_VERSION}" ]]; then + ZLIB_VERSION=1.3.1 +fi + +clone_with_ssh=false +while [ "$#" -gt 0 ]; do + case "$1" in + --swift-scheme) + SWIFT_VERSION="scheme:$2"; shift ;; + --swift-tag) + SWIFT_VERSION="tag:$2"; shift ;; + --swift-version) + SWIFT_VERSION="$2"; shift ;; + --musl-version) + MUSL_VERSION="$2"; shift ;; + --libxml2-version) + LIBXML2_VERSION="$2"; shift ;; + --curl-version) + CURL_VERSION="$2"; shift ;; + --boringssl-version) + BORINGSSL_VERSION="$2"; shift ;; + --icu-version) + ICU_VERSION="$2"; shift ;; + --zlib-version) + ZLIB_VERSION="$2"; shift ;; + --clone-with-ssh) + clone_with_ssh=true ;; + --source-dir) + source_dir="$2"; shift ;; + *) + usage; exit 0 ;; + esac + shift +done + +if [[ ! -z "$source_dir" ]]; then + mkdir -p "$source_dir" +else + source_dir=. +fi + +if [[ "$clone_with_ssh" == "true" ]]; then + github=git@github.com: + clone_arg=--clone-with-ssh +else + github=https://github.com/ + clone_arg=--clone +fi + +cd "$source_dir" + +# Fetch Swift +header "Fetching Swift" + +mkdir -p swift-project +pushd swift-project >/dev/null + +git clone ${github}apple/swift.git +cd swift + +# Get its dependencies +header "Fetching Swift Dependencies" + +extra_args=--skip-history +if [[ $SWIFT_VERSION == scheme:* ]]; then + utils/update-checkout ${clone_arg} --scheme ${SWIFT_VERSION#scheme:} ${extra_args} +elif [[ $SWIFT_VERSION == tag:* ]]; then + utils/update-checkout ${clone_arg} --tag ${SWIFT_VERSION#tag:} ${extra_args} +else + utils/update-checkout ${clone_arg} --tag swift-${SWIFT_VERSION}-RELEASE ${extra_args} +fi + +popd >/dev/null + +# Fetch Musl (can't clone using ssh) +header "Fetching Musl" + +git clone https://git.musl-libc.org/git/musl +pushd musl >/dev/null 2>&1 +git checkout v${MUSL_VERSION} +popd >/dev/null 2>&1 + +# Fetch libxml2 +header "Fetching libxml2" + +git clone ${github}GNOME/libxml2.git +pushd libxml2 >/dev/null 2>&1 +git checkout v${LIBXML2_VERSION} +popd >/dev/null 2>&1 + +# Fetch curl +header "Fetching curl" + +git clone ${github}curl/curl.git +pushd curl >/dev/null 2>&1 +git checkout curl-$(echo ${CURL_VERSION} | tr '.' '_') +popd >/dev/null 2>&1 + +# Fetch BoringSSL (also can't clone using ssh) +header "Fetching BoringSSL" + +git clone https://boringssl.googlesource.com/boringssl +pushd boringssl >/dev/null 2>&1 +git checkout ${BORINGSSL_VERSION} +popd >/dev/null 2>&1 + +# Fetch ICU +header "Fetching ICU" + +git clone ${github}unicode-org/icu.git +pushd icu >/dev/null 2>&1 +git checkout ${ICU_VERSION} +popd >/dev/null 2>&1 + +# Fetch zlib +header "Fetching zlib" + +git clone ${github}madler/zlib.git +pushd zlib >/dev/null 2>&1 +git checkout v${ZLIB_VERSION} +popd >/dev/null 2>&1 diff --git a/swift-ci/sdks/static-linux/scripts/fixtypes.py b/swift-ci/sdks/static-linux/scripts/fixtypes.py new file mode 100755 index 00000000..1423cfb1 --- /dev/null +++ b/swift-ci/sdks/static-linux/scripts/fixtypes.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 + +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Fix-up Types for Musl Headers +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +import re +import os +import sys + +class Definition (object): + """Represents a named definition, which may have conditions attached.""" + + def __init__(self, name, definition): + self.conditions = None + self.name = name + self.definition = definition + + def conditionalised(self, s): + """Output a sequence of nested `#if` conditions, as required, with + the text from `s` in the middle.""" + + if self.conditions is None: + return s + result = [] + indent = 0 + for cond in self.conditions: + result.append('{}#if {}'.format(' ' * indent, cond)) + indent += 1 + for line in s.splitlines(): + result.append(' ' * indent + line) + for cond in reversed(self.conditions): + indent -= 1 + result.append('{}#endif // {}'.format(' ' * indent, cond)) + return '\n'.join(result) + +class Type (Definition): + """Represents a `typedef`, which might require a `struct`.""" + + def __init__(self, name, definition): + super().__init__(name, definition) + self.requires = None + + def with_requires(self, s): + result = [] + + if self.requires: + for require in self.requires: + result.append('#include "{}.h"'.format(require)) + + result.append('') + + result.append(s) + + return self.conditionalised('\n'.join(result)) + + def __str__(self): + return self.with_requires( + 'typedef {} {};'.format(self.definition, self.name) + ) + +class Struct (Type): + def __str__(self): + return self.with_requires( + 'struct {} {};'.format(self.name, self.definition) + ) + +class Define (Definition): + def __str__(self): + return self.conditionalised( + '#define {} {}'.format(self.name, self.definition) + ) + +_define_re = re.compile(r'^#define (?P[_A-Za-z][_A-Za-z0-9]*) (?P.*)$') +_undef_re = re.compile(r'^#undef (?P[_A-Za-z][_A-Za-z0-9]*)(?: |$)') +_if_re = re.compile(r'^#if (?P.*)$') +_ifdef_re = re.compile(r'^#ifdef (?P[_A-Za-z][_A-Za-z0-9]*)$') +_ifndef_re = re.compile(r'^#ifndef (?P[_A-Za-z][_A-Za-z0-9]*)$') +_else_re = re.compile(r'^#else(?: |$)') +_elif_re = re.compile(r'^#elif (?P.*)$') +_endif_re = re.compile(r'^#endif(?: |$)') +_typedef_re = re.compile(r'^TYPEDEF (?P.*) (?P[_A-Za-z][_A-Za-z0-9]*);') +_struct_re = re.compile(r'^STRUCT (?P[_A-Za-z][_A-Za-z0-9]*) (?P.*);') +_typedef_struct_re = re.compile(r'^TYPEDEF (?Pstruct (?P[_A-Za-z][_A-Za-z0-9]*)) (?P[_A-Za-z][_A-Za-z0-9]*);') +_token_re = re.compile(r'[_A-Za-z][_A-Za-z0-9]*') + +def fix_types(arch_types, libc_types, defs_output, alltypes_output, output_dir): + """Take Musl's alltypes.h.in and process it into a set of discrete + header files, one per type, so that it's modularizable.""" + + defines=dict() + types=dict() + conditions=[] + + def expand_def(match): + name = match.group(0) + repl = defines.get(name, None) + if repl is None or repl[0].conditions: + return name + return repl[0].definition + + def expand(text): + return _token_re.sub(expand_def, text) + + def scan_requires(text): + requires = set() + for match in _token_re.finditer(text): + token = match.group(0) + if token in types: + requires.add(token) + return list(requires) + + def add_type(type, name=None): + if name is None: + name = type.name + curtypes = types.get(name, []) + for curt in curtypes: + if curt.conditions == type.conditions: + return + types[name] = curtypes + [type] + + def process(line): + line = line.strip() + + m = _define_re.match(line) + if m: + d = Define(m.group('name'), m.group('definition')) + if conditions: + d.conditions = conditions.copy() + defines[d.name] = defines.get(d.name, []) + [d] + return + + m = _undef_re.match(line) + if m: + del defines[m.group('name')] + return + + m = _typedef_struct_re.match(line) + if m: + t = Type(m.group('name'), expand(m.group('definition'))) + t.requires = ['struct_' + m.group('struct_name')] \ + + scan_requires(m.group('definition')) + if conditions: + t.conditions = conditions.copy() + add_type(t) + return + + m = _typedef_re.match(line) + if m: + t = Type(m.group('name'), expand(m.group('definition'))) + t.requires = scan_requires(m.group('definition')) + if conditions: + t.conditions = conditions.copy() + add_type(t) + return + + m = _struct_re.match(line) + if m: + s = Struct(m.group('name'), expand(m.group('definition'))) + s.requires = scan_requires(m.group('definition')) + if conditions: + s.conditions = conditions.copy() + add_type(s, name='struct_' + s.name) + return + + m = _if_re.match(line) + if m: + conditions.append(m.group('condition')) + return + m = _ifdef_re.match(line) + if m: + condition = 'defined({})'.format(m.group('name')) + conditions.append(condition) + return + m = _ifndef_re.match(line) + if m: + condition = '!defined({})'.format(m.group('name')) + conditions.append(condition) + return + m = _else_re.match(line) + if m: + cond = conditions.pop() + conditions.append('!({})'.format(cond)) + return + m = _elif_re.match(line) + if m: + cond = conditions.pop() + conditions.append('!({}) && ({})'.format(cond, m.group('condition'))) + return + m = _endif_re.match(line) + if m: + conditions.pop() + return + + with open(arch_types, "r") as fp: + for line in fp: + process(line) + with open(libc_types, 'r') as fp: + for line in fp: + process(line) + + with open(defs_output, 'w') as fp: + print("""// AUTO-GENERATED FILE: This was generated from alltypes.h.in +#ifndef __BITS_MUSL_DEFS_H +#define __BITS_MUSL_DEFS_H +""", file=fp) + + for _, define in defines.items(): + for d in define: + print("{}".format(d), file=fp) + + print(""" +#endif // __BITS_MUSL_DEFS_H +""", file=fp) + + with open(alltypes_output, 'w') as fp: + print("""// AUTO-GENERATED FILE: This was generated from alltypes.h.in + +#include """, file=fp) + + for name, _ in types.items(): + print(""" +#ifdef __NEED_{} +#include +#endif""".format(name, name + '.h'), file=fp) + + for name, defs in types.items(): + with open(os.path.join(output_dir, name + '.h'), 'w') as fp: + ucase_name = name.upper() + print("""// AUTO-GENERATED FILE: This was generated from alltypes.h.in + +#ifndef __BITS_TYPES_{}_H +#define __BITS_TYPES_{}_H + +#include +""".format(ucase_name, ucase_name), file=fp) + + for t in defs: + print("{}".format(t), file=fp) + + print("\n#endif // __BITS_TYPES_{}_H".format(ucase_name), file=fp) + + print('Found {} types and {} defines'.format(len(types), len(defines))) + +def main(argv): + if len(argv) != 6: + print("""usage: fixtypes + +Given an architecture specific `alltypes.h.in` and a main `alltypes.h.in`, +generate a set of header files, one per type, taking into account any +`#if` conditions that may apply. Also generate a separate header containing +any `#define`s that are found along the way. +""") + exit(0) + + arch_alltypes = argv[1] + alltypes = argv[2] + musldefs_h = argv[3] + alltypes_h = argv[4] + types_dir = argv[5] + + musldefs_dir = os.path.dirname(musldefs_h) + if musldefs_dir and musldefs_dir not in ('.', '..', '/'): + os.makedirs(musldefs_dir, exist_ok=True) + os.makedirs(types_dir, exist_ok=True) + + fix_types(arch_alltypes, alltypes, musldefs_h, alltypes_h, types_dir) + +if __name__ == '__main__': + main(sys.argv) diff --git a/swift-ci/sdks/static-linux/scripts/install-swift.sh b/swift-ci/sdks/static-linux/scripts/install-swift.sh new file mode 100755 index 00000000..0157d841 --- /dev/null +++ b/swift-ci/sdks/static-linux/scripts/install-swift.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# ===----------------------------------------------------------------------=== +# +# Swift Static SDK for Linux: Install Swift +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ===----------------------------------------------------------------------=== + +set -e + +echo "Installing Swift" + +# Get latest toolchain info +latest_build=$(curl -s ${SWIFT_WEBROOT}/latest-build.yml) +download=$(echo "$latest_build" | grep '^download: ' | sed 's/^download: //g') +download_signature=$(echo "$latest_build " | grep '^download_signature: ' | sed 's/^download_signature: //g') +download_dir=$(echo "$latest_build" | grep '^dir: ' | sed 's/^dir: //g') + +echo "Latest build is ${download_dir}" + +# Make a temporary directory +tmpdir=$(mktemp -d) +function cleanup { + rm -rf "$tmpdir" +} +trap cleanup EXIT + +pushd "$tmpdir" >/dev/null +export GNUPGHOME="$tmpdir" + +# Fetch the toolchain and signature +echo "Going to fetch ${SWIFT_WEBROOT}/${download_dir}/${download}" + +curl -fsSL "${SWIFT_WEBROOT}/${download_dir}/${download}" -o toolchain.tar.gz + +echo "Going to fetch ${SWIFT_WEBROOT}/${download_dir}/${download_signature}" + +curl -fsSL "${SWIFT_WEBROOT}/${download_dir}/${download_signature}" -o toolchain.sig + +echo "Fetching keys" + +curl -fsSL https://swift.org/keys/all-keys.asc | gpg --import - + +echo "Verifying signature" + +gpg --batch --verify toolchain.sig toolchain.tar.gz + +# Extract and install the toolchain +echo "Extracting Swift" + +mkdir -p /usr/local/swift +tar -xzf toolchain.tar.gz --directory /usr/local/swift --strip-components=2 +chmod -R o+r /usr/local/swift/lib/swift + +popd >/dev/null +