From e31bbc0d2dd7336fbc83d7850b760fb7d9affdbf Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Fri, 4 Jun 2021 12:00:23 +0000 Subject: Initial commit --- .gitignore | 8 + AUTHORS | 2 + CONTRIBUTING | 5 + COPYING | 13 + DCO | 37 ++ INSTALL | 169 ++++++++ Makefile | 149 +++++++ NEWS | 6 + README | 24 + configure | 482 +++++++++++++++++++++ doc/index.html | 97 +++++ doc/smtpd-starttls-proxy-io.html | 31 ++ doc/upgrade.html | 28 ++ package/deps-build | 2 + package/deps.mak | 8 + package/info | 4 + package/modes | 1 + package/targets.mak | 5 + .../deps-exe/smtpd-starttls-proxy-io | 1 + src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c | 419 ++++++++++++++++++ tools/gen-deps.sh | 93 ++++ tools/install.sh | 64 +++ 22 files changed, 1648 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CONTRIBUTING create mode 100644 COPYING create mode 100644 DCO create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100755 configure create mode 100644 doc/index.html create mode 100644 doc/smtpd-starttls-proxy-io.html create mode 100644 doc/upgrade.html create mode 100644 package/deps-build create mode 100644 package/deps.mak create mode 100644 package/info create mode 100644 package/modes create mode 100644 package/targets.mak create mode 100644 src/smtpd-starttls-proxy/deps-exe/smtpd-starttls-proxy-io create mode 100644 src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c create mode 100755 tools/gen-deps.sh create mode 100755 tools/install.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bb4729 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.so +*.so.* +/config.mak +/src/include/smtpd-starttls-proxy/config.h +/smtpd-starttls-proxy diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..7a708a1 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Main author: + Laurent Bercot diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 0000000..6279422 --- /dev/null +++ b/CONTRIBUTING @@ -0,0 +1,5 @@ + Please add a Signed-Off-By: line at the end of your commit, +which certifies that you have the right and authority to pass +it on as an open-source patch, as explicited in the Developer's +Certificate of Origin available in this project's DCO file, +or at https://developercertificate.org/ diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..639e498 --- /dev/null +++ b/COPYING @@ -0,0 +1,13 @@ +Copyright (c) 2021 Laurent Bercot + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/DCO b/DCO new file mode 100644 index 0000000..8201f99 --- /dev/null +++ b/DCO @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..4bfc049 --- /dev/null +++ b/INSTALL @@ -0,0 +1,169 @@ +Build Instructions +------------------ + +* Requirements + ------------ + + - A Linux-based system with a standard C development environment + - GNU make version 3.81 or later + - skalibs version 2.10.0.3 or later: https://skarnet.org/software/skalibs/ + - s6 version 2.10.0.3 or later: https://skarnet.org/software/s6/ + - s6-networking version 2.4.2.0 or later: + https://skarnet.org/software/s6-networking/ + + This software will run on any operating system that implements +POSIX.1-2008, available at: + https://pubs.opengroup.org/onlinepubs/9699919799/ + + +* Standard usage + -------------- + + ./configure && make && sudo make install + + will work for most users. + It will install the binaries in /bin. + + You can strip the binaries and libraries of their extra symbols via +"make strip" before the "make install" phase. It will shave a few bytes +off them. + + +* Customization + ------------- + + You can customize paths via flags given to configure. + See ./configure --help for a list of all available configure options. + + +* Environment variables + --------------------- + + Controlling a build process via environment variables is a big and +dangerous hammer. You should try and pass flags to configure instead; +nevertheless, a few standard environment variables are recognized. + + If the CC environment variable is set, its value will override compiler +detection by configure. The --host=HOST option will still add a HOST- +prefix to the value of CC. + + The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags +auto-detected by configure. To entirely override the flags set by +configure instead, use make variables. + + +* Make variables + -------------- + + You can invoke make with a few variables for more configuration. + + CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and +CROSS_COMPILE can all be overridden on the make command line. This is +an even bigger hammer than running ./configure with environment +variables, so it is advised to only do this when it is the only way of +obtaining the behaviour you want. + + DESTDIR can be given on the "make install" command line in order to +install to a staging directory. + + +* Shared libraries + ---------------- + + Software from skarnet.org is small enough that shared libraries are +generally not worth using. Static linking is simpler and incurs less +runtime overhead and less points of failure: so by default, shared +libraries are not built and binaries are linked against the static +versions of the skarnet.org libraries. Nevertheless, you can: + * build shared libraries: --enable-shared + * link binaries against shared libraries: --disable-allstatic + + +* Static binaries + --------------- + + By default, binaries are linked against static versions of all the +libraries they depend on, except for the libc. You can enforce +linking against the static libc with --enable-static-libc. + + Be aware that the GNU libc behaves badly with static linking and +produces huge executables, which is why it is not the default. +Other libcs are better suited to static linking, for instance +musl: https://musl-libc.org/ + + +* Cross-compilation + ----------------- + + skarnet.org packages centralize all the difficulty of +cross-compilation in one place: skalibs. Once you have +cross-compiled skalibs, the rest is easy. + + * Use the --host=HOST option to configure, HOST being the triplet +for your target. + * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-) +are accessible via your PATH environment variable. + * Make sure to use the correct version of skalibs for your target, +and the correct sysdeps directory, making use of the +--with-include, --with-lib, --with-dynlib and --with-sysdeps +options as necessary. + + +* The slashpackage convention + --------------------------- + + The slashpackage convention (http://cr.yp.to/slashpackage.html) +is a package installation scheme that provides a few guarantees +over other conventions such as the FHS, for instance fixed +absolute pathnames. skarnet.org packages support it: use the +--enable-slashpackage option to configure, or +--enable-slashpackage=DIR for a prefixed DIR/package tree. +This option will activate slashpackage support during the build +and set slashpackage-compatible installation directories. +If $package_home is the home of the package, defined as +DIR/package/$category/$package-$version with the variables +read from the package/info file, then: + + --dynlibdir is set to $package_home/library.so + --bindir is set to $package_home/command + --sbindir is also set to $package_home/command (slashpackage +differentiates root-only binaries by their Unix rights, not their +location in the filesystem) + --libexecdir is also set to $package_home/command (slashpackage +does not need a specific directory for internal binaries) + --libdir is set to $package_home/library + --includedir is set to $package_home/include + + --prefix is pretty much ignored when you use --enable-slashpackage. +You should probably not use both --enable-slashpackage and --prefix. + + When using slashpackage, two additional Makefile targets are +available after "make install": + - "make update" changes the default version of the software to the +freshly installed one. (This is useful when you have several installed +versions of the same software, which slashpackage supports.) + - "make -L global-links" adds links from /command and /library.so to the +default version of the binaries and shared libraries. The "-L" option to +make is necessary because targets are symbolic links, and the default make +behaviour is to check the pointed file's timestamp and not the symlink's +timestamp. + + +* Absolute pathnames + ------------------ + + You may want to use fixed absolute pathnames even if you're not +following the slashpackage convention: for instance, the Nix packaging +system prefers calling binaries with immutable paths rather than rely on +PATH resolution. If you are in that case, use the --enable-absolute-paths +option to configure. This will ensure that programs calling binaries from +this package will call them with their full installation path (in bindir) +without relying on a PATH search. + + +* Out-of-tree builds + ------------------ + + skarnet.org packages do not support out-of-tree builds. They +are small, so it does not cost much to duplicate the entire +source tree if parallel builds are needed. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cd6c7f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,149 @@ +# +# This Makefile requires GNU make. +# +# Do not make changes here. +# Use the included .mak files. +# + +it: all + +make_need := 3.81 +ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))" +fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer) +endif + +CC = $(error Please use ./configure first) + +STATIC_LIBS := +SHARED_LIBS := +INTERNAL_LIBS := +EXTRA_TARGETS := +LIB_DEFS := + +define library_definition +LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy +ifdef DO_SHARED +SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy +endif +ifdef DO_STATIC +STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy +endif +endef + +-include config.mak +include package/targets.mak + +$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var)))) + +include package/deps.mak + +version_m := $(basename $(version)) +version_M := $(basename $(version_m)) +version_l := $(basename $(version_M)) +CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS) +CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS) +ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) +CFLAGS_SHARED := -fPIC +else +CFLAGS_SHARED := +endif +LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS) +AR := $(CROSS_COMPILE)ar +RANLIB := $(CROSS_COMPILE)ranlib +STRIP := $(CROSS_COMPILE)strip +INSTALL := ./tools/install.sh + +ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS) +ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS) +ALL_INCLUDES := $(wildcard src/include/$(package)/*.h) + +all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES) + +clean: + @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS) + +distclean: clean + @exec rm -f config.mak src/include/$(package)/config.h + +tgz: distclean + @. package/info && \ + rm -rf /tmp/$$package-$$version && \ + cp -a . /tmp/$$package-$$version && \ + cd /tmp && \ + tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \ + exec rm -rf /tmp/$$package-$$version + +strip: $(ALL_LIBS) $(ALL_BINS) +ifneq ($(strip $(STATIC_LIBS)),) + exec $(STRIP) -x -R .note -R .comment $(STATIC_LIBS) +endif +ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),) + exec $(STRIP) -R .note -R .comment $(ALL_BINS) $(SHARED_LIBS) +endif + +install: install-dynlib install-libexec install-bin install-lib install-include +install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so) +install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%) +install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%) +install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a) +install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) +install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%) + +ifneq ($(exthome),) + +$(DESTDIR)$(exthome): $(DESTDIR)$(home) + exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome) + +update: $(DESTDIR)$(exthome) + +global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) + +$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/% + exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$( + + Please use the mailing-list for +questions about smtpd-starttls-proxy. diff --git a/configure b/configure new file mode 100755 index 0000000..b54c325 --- /dev/null +++ b/configure @@ -0,0 +1,482 @@ +#!/bin/sh + +cd `dirname "$0"` +. package/info + +usage () { +cat </dev/null 2>&1 && { echo "$1" ; return 0 ; } +$1 +EOF + echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g" +} + +fail () { + echo "$*" + exit 1 +} + +fnmatch () { + eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac" +} + +cmdexists () { + type "$1" >/dev/null 2>&1 +} + +trycc () { + test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*" +} + +stripdir () { + while eval "fnmatch '*/' \"\${$1}\"" ; do + eval "$1=\${$1%/}" + done +} + +tryflag () { + echo "Checking whether compiler accepts $2 ..." + echo "typedef int x;" > "$tmpc" + if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o "$tmpo" "$tmpc" >/dev/null 2>&1 ; then + echo " ... yes" + eval "$1=\"\${$1} \$2\"" + eval "$1=\${$1# }" + return 0 + else + echo " ... no" + return 1 + fi +} + +tryldflag () { + echo "Checking whether linker accepts $2 ..." + echo "typedef int x;" > "$tmpc" + if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o "$tmpe" "$tmpc" >/dev/null 2>&1 ; then + echo " ... yes" + eval "$1=\"\${$1} \$2\"" + eval "$1=\${$1# }" + return 0 + else + echo " ... no" + return 1 + fi +} + + +# Actual script + +CC_AUTO= +CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include" +CPPFLAGS_POST="$CPPFLAGS" +CPPFLAGS= +CFLAGS_AUTO="-pipe -Wall" +CFLAGS_POST="$CFLAGS" +CFLAGS=-O2 +LDFLAGS_AUTO= +LDFLAGS_POST="$LDFLAGS" +LDFLAGS= +LDFLAGS_NOSHARED= +LDFLAGS_SHARED=-shared +prefix= +exec_prefix='$prefix' +dynlibdir='$prefix/lib' +libexecdir='$exec_prefix/libexec' +bindir='$exec_prefix/bin' +libdir='$prefix/lib/$package' +includedir='$prefix/include' +sysdeps='$prefix/lib/skalibs/sysdeps' +manualsysdeps=false +shared=false +static=true +allpic=true +slashpackage=false +abspath=false +usensss=false +sproot= +home= +exthome= +allstatic=true +evenmorestatic=false +addincpath='' +addlibspath='' +addlibdpath='' +vpaths='' +vpathd='' +build= + +for arg ; do + case "$arg" in + --help) usage ;; + --prefix=*) prefix=${arg#*=} ;; + --exec-prefix=*) exec_prefix=${arg#*=} ;; + --dynlibdir=*) dynlibdir=${arg#*=} ;; + --libexecdir=*) libexecdir=${arg#*=} ;; + --bindir=*) bindir=${arg#*=} ;; + --libdir=*) libdir=${arg#*=} ;; + --includedir=*) includedir=${arg#*=} ;; + --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;; + --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;; + --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;; + --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;; + --enable-shared|--enable-shared=yes) shared=true ;; + --disable-shared|--enable-shared=no) shared=false ;; + --enable-static|--enable-static=yes) static=true ;; + --disable-static|--enable-static=no) static=false ;; + --enable-allstatic|--enable-allstatic=yes) allstatic=true ;; + --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;; + --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;; + --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;; + --enable-all-pic|--enable-all-pic=yes) allpic=true ;; + --disable-all-pic|--enable-all-pic=no) allpic=false ;; + --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;; + --enable-slashpackage) sproot= ; slashpackage=true ;; + --disable-slashpackage) sproot= ; slashpackage=false ;; + --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;; + --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;; + --enable-nsss|--enable-nsss=yes) usensss=true ;; + --disable-nsss|--enable-nsss=no) usensss=false ;; + --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; + --host=*|--target=*) target=${arg#*=} ;; + --build=*) build=${arg#*=} ;; + -* ) echo "$0: unknown option $arg" ;; + *=*) ;; + *) target=$arg ;; + esac +done + +# Add /usr in the default default case +if test -z "$prefix" ; then + if test "$libdir" = '$prefix/lib/$package' ; then + libdir=/usr/lib/$package + fi + if test "$includedir" = '$prefix/include' ; then + includedir=/usr/include + fi + if test "$sysdeps" = '$prefix/lib/skalibs/sysdeps' ; then + sysdeps=/usr/lib/skalibs/sysdeps + fi +fi + +# Expand installation directories +stripdir prefix +for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do + eval tmp=\${$i} + eval $i=$tmp + stripdir $i +done + +# Get usable temp filenames +i=0 +set -C +while : ; do + i=$(($i+1)) + tmpc="./tmp-configure-$$-$PPID-$i.c" + tmpo="./tmp-configure-$$-$PPID-$i.o" + tmpe="./tmp-configure-$$-$PPID-$i.tmp" + 2>|/dev/null > "$tmpc" && break + 2>|/dev/null > "$tmpo" && break + 2>|/dev/null > "$tmpe" && break + test "$i" -gt 50 && fail "$0: cannot create temporary files" +done +set +C +trap 'rm -f "$tmpc" "$tmpo" "$tmpe"' EXIT ABRT INT QUIT TERM HUP + +# Set slashpackage values +if $slashpackage ; then + home=${sproot}/package/${category}/${package}-${version} + exthome=${sproot}/package/${category}/${package} + if $manualsysdeps ; then + : + else + sysdeps=${sproot}/package/prog/skalibs/sysdeps + fi + extbinprefix=${exthome}/command + dynlibdir=${home}/library.so + bindir=${home}/command + libdir=${home}/library + libexecdir=$bindir + includedir=${home}/include + while read dep condvar ; do + if test -n "$condvar" ; then + eval "cond=$condvar" + else + cond=true + fi + if $cond ; then + addincpath="$addincpath -I${sproot}${dep}/include" + vpaths="$vpaths ${sproot}${dep}/library" + addlibspath="$addlibspath -L${sproot}${dep}/library" + vpathd="$vpathd ${sproot}${dep}/library.so" + addlibdpath="$addlibdpath -L${sproot}${dep}/library.so" + fi + done < package/deps-build +fi + +# Find a C compiler to use +if test -n "$target" && test x${build} != x${target} ; then + cross=${target}- +else + cross= +fi +echo "Checking for C compiler..." +trycc ${CC} +if test -n "$CC_AUTO" ; then + b=`basename "$CC"` + adjust_cross=false + if test "$b" != "$CC" ; then + adjust_cross=true + echo "$0: warning: compiler $CC is declared with its own path. If it's not accessible via PATH, you will need to pass AR, RANLIB and STRIP make variables to the make invocation." 1>&2 + fi + if test -n "$cross" ; then + if test "$b" = "${b##$cross}" ; then + echo "$0: warning: compiler $CC is declared as a cross-compiler for target $target but does not start with prefix ${cross}" 1>&2 + elif $adjust_cross ; then + cross=`dirname "$CC"`/"$cross" + fi + fi +fi +trycc ${cross}gcc +trycc ${cross}clang +trycc ${cross}cc +test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; } +echo " ... $CC_AUTO" +echo "Checking whether C compiler works... " +echo "typedef int x;" > "$tmpc" +if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o "$tmpo" "$tmpc" 2>"$tmpe" ; then + echo " ... yes" +else + echo " ... no. Compiler output follows:" + cat < "$tmpe" + exit 1 +fi + +echo "Checking target system type..." +if test -z "$target" ; then + if test -n "$build" ; then + target=$build ; + else + target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown + fi +fi +echo " ... $target" +if test ! -d $sysdeps || test ! -f $sysdeps/target ; then + echo "$0: error: $sysdeps is not a valid sysdeps directory" + exit 1 +fi +if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then + echo "$0: error: target $target does not match the contents of $sysdeps/target" + exit 1 +fi + +spawn_lib=$(cat $sysdeps/spawn.lib) +socket_lib=$(cat $sysdeps/socket.lib) +sysclock_lib=$(cat $sysdeps/sysclock.lib) +timer_lib=$(cat $sysdeps/timer.lib) +util_lib=$(cat $sysdeps/util.lib) + +if $allpic ; then + tryflag CPPFLAGS_AUTO -fPIC +fi +tryflag CFLAGS_AUTO -std=c99 +tryflag CFLAGS -fomit-frame-pointer +tryflag CFLAGS_AUTO -fno-exceptions +tryflag CFLAGS_AUTO -fno-unwind-tables +tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables +tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration +tryflag CPPFLAGS_AUTO -Werror=implicit-int +tryflag CPPFLAGS_AUTO -Werror=pointer-sign +tryflag CPPFLAGS_AUTO -Werror=pointer-arith +tryflag CFLAGS_AUTO -ffunction-sections +tryflag CFLAGS_AUTO -fdata-sections + +tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment +tryldflag LDFLAGS_AUTO -Wl,--sort-common + +CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}" + +if $evenmorestatic ; then + LDFLAGS_NOSHARED=-static +fi + +if $shared ; then + tryldflag LDFLAGS -Wl,--hash-style=both +fi + +LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}" + +if test -z "$vpaths" ; then + while read dep ; do + base=$(basename $dep) ; + vpaths="$vpaths /usr/lib/$base" + addlibspath="$addlibspath -L/usr/lib/$base" + done < package/deps-build +fi + +if $allstatic ; then + LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}" + tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections +else + LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}" +fi + +echo "Creating config.mak..." +cmdline=$(quote "$0") +for i ; do cmdline="$cmdline $(quote "$i")" ; done +exec 3>&1 1>config.mak +cat << EOF +# This file was generated by: +# $cmdline +# Any changes made here will be lost if configure is re-run. + +target := $target +package := $package +prefix := $prefix +exec_prefix := $exec_prefix +dynlibdir := $dynlibdir +libexecdir := $libexecdir +bindir := $bindir +libdir := $libdir +includedir := $includedir +sysdeps := $sysdeps +slashpackage := $slashpackage +sproot := $sproot +version := $version +home := $home +exthome := $exthome +SPAWN_LIB := ${spawn_lib} +SOCKET_LIB := ${socket_lib} +SYSCLOCK_LIB := ${sysclock_lib} +TIMER_LIB := ${timer_lib} +UTIL_LIB := ${util_lib} + +CC := $CC_AUTO +CPPFLAGS_AUTO := $CPPFLAGS_AUTO +CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST +CFLAGS_AUTO := $CFLAGS_AUTO +CFLAGS := $CFLAGS $CFLAGS_POST +LDFLAGS_AUTO := $LDFLAGS_AUTO +LDFLAGS := $LDFLAGS $LDFLAGS_POST +LDFLAGS_SHARED := $LDFLAGS_SHARED +LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED +CROSS_COMPILE := $cross + +vpath lib%.a$vpaths +vpath lib%.so$vpathd +EOF +if $allstatic ; then + echo ".LIBPATTERNS := lib%.a" + echo "DO_ALLSTATIC := 1" +else + echo ".LIBPATTERNS := lib%.so" +fi +if $static ; then + echo "DO_STATIC := 1" +else + echo "DO_STATIC :=" +fi +if $shared ; then + echo "DO_SHARED := 1" +else + echo "DO_SHARED :=" +fi +if $allpic ; then + echo "STATIC_LIBS_ARE_PIC := 1" +else + echo "STATIC_LIBS_ARE_PIC :=" +fi +if $usensss ; then + echo "LIBNSSS := -lnsss" + echo "MAYBEPTHREAD_LIB := -lpthread" +else + echo "LIBNSSS :=" + echo "MAYBEPTHREAD_LIB :=" +fi + +exec 1>&3 3>&- +echo " ... done." + +echo "Creating src/include/${package}/config.h..." +mkdir -p -m 0755 src/include/${package} +exec 3>&1 1> src/include/${package}/config.h +cat <&3 3>&- +echo " ... done." diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..39229f9 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,97 @@ + + + + + + smtpd-starttls-proxy - A proxy implementing STARTTLS in front of SMTP servers that do not + + + + + + +

+Software
+skarnet.org +

+ +

smtpd-starttls-proxy

+ +

What is it ?

+ +

+ smtpd-starttls-proxy is a program implementing STARTTLS for mail servers. +

+ +
+ +

Installation

+ +

Requirements

+ +
    +
  • A POSIX-compliant system with a standard C development environment
  • +
  • GNU make, version 3.81 or later
  • +
  • skalibs version +2.10.0.3 or later. It's a build-time requirement. It's also a run-time +requirement if you link against the shared version of the skalibs +library.
  • +
  • s6 version +2.10.0.3 or later. It's a build-time and run-time requirement.
  • +
  • s6-networking version +2.4.2.0 or later. It's a build-time and run-time requirement.
  • +
+ +

Licensing

+ +

+ smtpd-starttls-proxy is free software. It is available under the +ISC license. +

+ +

Download

+ + + +

Compilation

+ +
    +
  • See the enclosed INSTALL file for installation details.
  • +
+ +

Upgrade notes

+ +
    +
  • This page lists the differences to be aware of between +the previous versions of smtpd-starttls-proxy and the current one.
  • +
+ +
+ +

Reference

+ +

Commands

+ + + +

Related resources

+ +
    +
  • smtpd-starttls-proxy is discussed on the +skaware mailing-list.
  • +
+ + + diff --git a/doc/smtpd-starttls-proxy-io.html b/doc/smtpd-starttls-proxy-io.html new file mode 100644 index 0000000..9f699b9 --- /dev/null +++ b/doc/smtpd-starttls-proxy-io.html @@ -0,0 +1,31 @@ + + + + + + smtpd-starttls-proxy: the smtpd-starttls-proxy-io program + + + + + + +

+smtpd-starttls-proxy
+Software
+skarnet.org +

+ +

The smtpd-starttls-proxy-io program

+ +

Interface

+ +
+     smtpd-starttls-proxy-io server...
+
+ +
    +
+ + + diff --git a/doc/upgrade.html b/doc/upgrade.html new file mode 100644 index 0000000..b93cb58 --- /dev/null +++ b/doc/upgrade.html @@ -0,0 +1,28 @@ + + + + + + smtpd-starttls-proxy: how to upgrade + + + + + + +

+smtpd-starttls-proxy
+Software
+skarnet.org +

+ +

What has changed in smtpd-starttls-proxy

+ +

in 0.0.1.0

+ +
    +
  • Initial release.
  • +
+ + + diff --git a/package/deps-build b/package/deps-build new file mode 100644 index 0000000..b099b0a --- /dev/null +++ b/package/deps-build @@ -0,0 +1,2 @@ +/package/prog/skalibs +/package/admin/s6 diff --git a/package/deps.mak b/package/deps.mak new file mode 100644 index 0000000..e6791f9 --- /dev/null +++ b/package/deps.mak @@ -0,0 +1,8 @@ +# +# This file has been generated by tools/gen-deps.sh +# + +src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.o src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.lo: src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c + +smtpd-starttls-proxy-io: EXTRA_LIBS := -lskarnet +smtpd-starttls-proxy-io: src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.o diff --git a/package/info b/package/info new file mode 100644 index 0000000..e5da603 --- /dev/null +++ b/package/info @@ -0,0 +1,4 @@ +package=smtpd-starttls-proxy +version=0.0.1.0 +category=mail +package_macro_name=SMTPD_STARTTLS_PROXY diff --git a/package/modes b/package/modes new file mode 100644 index 0000000..07461a5 --- /dev/null +++ b/package/modes @@ -0,0 +1 @@ +smtpd-starttls-proxy-io 0755 diff --git a/package/targets.mak b/package/targets.mak new file mode 100644 index 0000000..9faea17 --- /dev/null +++ b/package/targets.mak @@ -0,0 +1,5 @@ +BIN_TARGETS := \ +smtpd-starttls-proxy-io + +LIBEXEC_TARGETS := + diff --git a/src/smtpd-starttls-proxy/deps-exe/smtpd-starttls-proxy-io b/src/smtpd-starttls-proxy/deps-exe/smtpd-starttls-proxy-io new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/smtpd-starttls-proxy/deps-exe/smtpd-starttls-proxy-io @@ -0,0 +1 @@ +-lskarnet diff --git a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c new file mode 100644 index 0000000..8605345 --- /dev/null +++ b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c @@ -0,0 +1,419 @@ +/* ISC license. */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define USAGE "smtpd-starttls-proxy-io prog..." +#define dieusage() strerr_dieusage(100, USAGE) +#define dienomem() strerr_diefu1sys(111, "alloc") + +#define reset_timeout() tain_addsec_g(&deadline, 300000) + +static int fd_control ; +static int sslfds[2] ; +static int wantexec = 0 ; + +typedef struct io_s io_t, *io_t_ref ; +struct io_s { + buffer in ; + bufalloc out ; + stralloc indata ; + char buf[BUFFER_INSIZE] ; +} ; + +static io_t io[2] = +{ + [0] = { .in = BUFFER_INIT(&buffer_read, 0, io[0].buf, BUFFER_INSIZE), out = BUFALLOC_INIT(&fd_write, 1), .indata = STRALLOC_ZERO, .buf = "" }, + [1] = { .in = BUFFER_ZERO, out = BUFALLOC_ZERO, .indata = STRALLOC_ZERO, .buf = "" } +} ; + + + /* Server answer processing */ + +typedef int cbfunc (char const *) ; +typedef cbfunc cbfunc_ref ; + +typedef struct cbnode_s cbnode, *cbnode_ref ; +struct cbnode_s +{ + cbnode *prev ; + cbnode *next ; + cbfunc_ref f ; +} ; + +static cbnode cbsentinel = { .prev = &cbsentinel, .next = &cbsentinel, .f = 0 } + +static void cbfunc_enqueue (cbfunc_ref f) +{ + cbnode *node = alloc(sizeof(cbnode)) ; + if (!node) dienomem() ; + node->f = f ; + node->next = &cbsentinel ; + node->prev = cbsentinel.prev ; + cbsentinel.prev->next = node ; + cbsentinel.prev = node ; +} + +static void cbfunc_wedge (cbfunc_ref f) +{ + cbnode *node = alloc(sizeof(cbnode)) ; + if (!node) dienomem() ; + node->f = f ; + node->next = cbsentinel.next ; + node->prev = &cbsentinel ; + cbsentinel.next->prev = node ; + cbsentinel.next = node ; +} + +static void cbfunc_dequeue (void) +{ + cbnode *node = cbsentinel.next ; + node->next->prev = node->prev ; + cbsentinel.next = node->next ; + alloc_free(node) ; +} + +static inline void transfer_to_client (char const *s) +{ + if (!bufalloc_puts(&io[0].out, s)) dienomem() ; +} + +static int answer_forward (char const *s) +{ + transfer_to_client(s) ; + return 1 ; +} + +static int answer_ehlo (char const *s) +{ + transfer_to_client(s) ; + if (s[0] == '2' && case_starts(s+4, "starttls")) + strerr_warni1x("server seems to support STARTTLS natively") ; + return s[3] == ' ' ; +} + +static int trigger_starttls (char const *s) +{ + if (s[0] != '2') strerr_diefu3x(111, "STARTTLS: RSET failed, server answered: " , s) ; + return 1 ; +} + +static void process_server_line (char const *s) +{ + if (s[0] < '0' || s[0] > '5' + || s[1] < '0' || s[1] > '9' + || s[2] < '0' || s[2] > '9' + || (s[3] != ' ' && s[3] != '-')) + strerr_dief1x(100, "server is not speaking SMTP") ; + if ((*cbsentinel.next->f)(s)) cbfunc_dequeue() ; +} + + /* Client command processing */ + +typedef void cmdfunc (char const *, size_t) ; +typedef cmdfunc cmdfunc_ref ; + +struct cmdmap_s +{ + char const *name ; + cmdfunc_ref f ; +} ; + +typedef void cmdfunc (char const *, size_t) ; +typedef cmdfunc cmdfunc_ref ; + +typedef struct cmdmap_s cmdmap, *cmdmap_ref ; +struct cmdmap_s +{ + char const *name ; + cmdfunc_ref f ; +} ; + +static int command_enqueue (char const *s, cbfunc_ref f) +{ + if (!bufalloc_puts(&io[1].out, s)) dienomem() ; + cbfunc_enqueue(f) ; + return 0 ; +} + +static void answer_enqueue (char const *s) +{ + if (!bufalloc_puts(&io[0].out, s)) dienomem() ; +} + +static int do_noop (char const *s) +{ + (void)s ; + answer_enqueue("250 OK\r\n") ; + return 0 ; +} + +static int command_forward (char const *s) +{ + return command_enqueue(s, &answer_forward) ; +} + +static int do_rcpt (char const *s) +{ + (void)s ; + answer_enqueue("503 MAIL first (#5.5.1)\r\n") ; + return 0 ; +} + +static void do_ehlo (char const *s) +{ + return command_enqueue(s, &answer_ehlo) ; +} + +static int do_notls (char const *s) +{ + if (!bufalloc_puts(&io[1].out, s)) dienomem() ; + fd_close(fd_control) ; + fd_close(sslfds[1]) ; + fd_close(sslfds[0]) ; + wantexec = 1 ; + return 1 ; +} + +static int do_starttls (char const *s) +{ + command_enqueue("RSET\r\n", &trigger_starttls) ; + wantexec = 2 ; + return 0 ; +} + +static cmdmap const commands[] = +{ + { .name = "noop", .f = &do_noop }, + { .name = "help", .f = &command_forward }, + { .name = "vrfy", .f = &command_forward }, + { .name = "expn", .f = &command_forward }, + { .name = "quit", .f = &command_forward }, + { .name = "rcpt", .f = &do_rcpt }, + { .name = "ehlo", .f = &do_ehlo }, + { .name = "helo", .f = &do_notls }, + { .name = "mail", .f = &do_notls }, + { .name = "starttls", .f = &do_starttls }, + { .name = 0, .f = 0 } +} ; + +static int process_client_line (char const *s) +{ + cmdmap const *cmd = commands ; + for (cmdmap const *cmd = commands ; cmd->name ; cmd++) + if (case_starts(s, cmd->name)) break ; + if (cmd->name) + { + size_t len = strlen(cmd->name) ; + if (s[len] == ' ' || s[len] == '\r' || s[len] == '\n') + return (*cmd->f)(s) ; + } + answer_enqueue("502 unimplemented (#5.5.1)\r\n") ; + return 0 ; +} + + + /* Engine */ + +static void handle_signals (void) +{ + for (;;) switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read()") ; + case 0 : return ; + case SIGCHLD : wait_reap() ; break ; + default : break ; + } +} + +int main (int argc, char const *const *argv) +{ + iopause_fd x[5] = + { + [0] = { .events = IOPAUSE_READ }, + [1] = { .fd = 0 }, + [2] = { .fd = 1 } + [3] = { .events = IOPAUSE_READ } + } + tain_t deadline ; + PROG = "smtpd-starttls-proxy-io" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "", &l) ; + if (opt == -1) break ; + switch (opt) + { + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + { + unsigned int u ; + char const *x = getenv("SSLCTLFD") ; + if (!x) strerr_dienotset(100, "SSLCTLFD") ; + if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLCTLFD") ; + fd_control = u ; + x = getenv("SSLREADFD") ; + if (!x) strerr_dienotset(100, "SSLREADFD") ; + if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLREADFD") ; + sslfds[0] = u ; + x = getenv("SSLWRITEFD") ; + if (!x) strerr_dienotset(100, "SSLWRITEFD") ; + if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLWRITEFD") ; + sslfds[1] = u ; + } + + if (ndelay_on(0) < 0 || ndelay_on(1) < 0) + strerr_diefu1sys(111, "make stdin/stdout non-blocking") ; + x[0].fd = selfpipe_init() ; + if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + { + sigset_t set ; + sigemptyset(&set) ; + sigaddset(&set, SIGCHLD) ; + if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; + } + { + int fd[2] ; + if (!child_spawn2(argv[0], argv, (char const *const *)environ, fd)) + if (ndelay_on(fd[0]) < 0 || ndelay_on(fd[1]) < 0) + strerr_diefu1sys(111, "make server fds non-blocking") ; + buffer_init(&io[1].in, &buffer_read, fd[0], io[1].buf, BUFFER_INSIZE) ; + bufalloc_init(&io[1].out, &fd_write, fd[1]) ; + x[3].fd = fd[0] ; x[4].fd = fd[1] ; + } + + tain_now_set_stopwatch_g() ; + reset_timeout() ; + + cbfunc_enqueue(&answer_forward) ; + + for (;;) + { + int r ; + if (!bufalloc_len(&io[0].out) && (x[3].fd == -1 || (cbsentinel.next == &cbsentinel && wantexec))) break ; + x[1].events = wantexec ? 0 : IOPAUSE_READ ; + x[2].events = bufalloc_len(&io[0].out) ? IOPAUSE_WRITE : 0 ; + x[4].events = bufalloc_len(&io[1].out) ? IOPAUSE_WRITE : 0 ; + r = iopause_g(x, 5, &deadline) ; + if (r == -1) strerr_diefu1sys(111, "iopause") ; + if (!r) strerr_dief1x(99, "timed out") ; + for (size_t i = 0 ; i < 5 ; i++) if (x[0].revents & IOPAUSE_EXCEPT) x[0].revents |= IOPAUSE_READ | IOPAUSE_WRITE ; + + if (x[0].revents & IOPAUSE_READ) handle_signals() ; + + if (x[2].events & x[2].revents & IOPAUSE_WRITE) + { + reset_timeout() ; + if (!bufalloc_flush(&io[0].out) && !error_isagain(errno)) + strerr_diefu1sys(111, "write to client") ; + } + + if (x[4].events & x[4].revents & IOPAUSE_WRITE) + { + reset_timeout() ; + if (!bufalloc_flush(&io[1].out) && !error_isagain(errno)) + strerr_diefu1sys(111, "write to server") ; + } + + if (x[3].revents & IOPAUSE_READ) + { + reset_timeout() ; + for (;;) + { + int r = skagetln(&io[1].in, &io[1].indata, '\n') ; + if (r < 0) + { + if (error_isagain(errno)) break ; + else strerr_diefu1sys(111, "read line from server") ; + } + if (!r) + { + x[4].fd = -1 ; + x[3].fd = -1 ; + wantexec = 0 ; + break ; + } + if (!stralloc_0(&io[1].indata)) dienomem() ; + process_server_line(io[1].indata.s) ; + io[1].indata.len = 0 ; + } + } + + if (x[1].revents & IOPAUSE_READ) + { + reset_timeout() ; + for (;;) + { + int r = skagetln(&io[0].in, &io[0].indata, '\n') ; + if (r < 0) + { + if (error_isagain(errno)) break ; + else strerr_diefu1sys(111, "read line from client") ; + } + if (!r) return 0 ; + if (!stralloc_0(&io[0].indata)) dienomem() ; + if (process_client_line(io[0].indata.s)) break ; + io[0].indata.len = 0 ; + } + } + } + + if (!wantexec) return 0 ; + if (wantexec >= 2) + { + if (fd_write(fd_control, "Y", 1) < 0) + strerr_diefu1sys(111, "send ucspi-tls start command") ; + fd_shutdown(fd_control, 1) ; + for (;;) + { + ssize_t r = fd_read(fd_control, io[1].buf, BUFFER_INSIZE) ; + if (r < 0) strerr_diefu1sys(111, "read handshake environment") ; + if (!r) break ; + } + fd_close(fd_control) ; + if (fd_move2(0, sslfds[0], 1, sslfds[1]) == -1) + strerr_diefu1sys(111, "move fds") ; + } + if (io[0].indata.len) + { + if (!bufalloc_puts(&io[1].out, io[0].indata.s)) dienomem() ; + io[0].indata.len = 0 ; + if (!bufalloc_timed_flush_g(&io[1].out, &deadline)) strerr_dief1x(99, "timed out") ; + } + { + char fmtr[UINT_FMT] ; + char fmtw[UINT_FMT] ; + char const *newargv[7] = { S6_EXTBINPREFIX "s6-ioconnect", "-r", fmtr, "-w", fmtw, 0, 0 } ; + fmtr[uint_fmt(fmtr, x[3].fd)] = 0 ; + fmtw[uint_fmt(fmtw, x[4].fd)] = 0 ; + if (wantexec == 1) newargv[5] = "-01" ; + xexec(newargv) ; + } +} diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh new file mode 100755 index 0000000..27e5b3e --- /dev/null +++ b/tools/gen-deps.sh @@ -0,0 +1,93 @@ +#!/bin/sh -e + +. package/info + +echo '#' +echo '# This file has been generated by tools/gen-deps.sh' +echo '#' +echo + +for dir in src/include/${package} src/* ; do + for file in $(ls -1 $dir | grep -- \\.h$) ; do + { + grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; + grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 + } | sort -u | { + deps= + while read dep ; do + if echo $dep | grep -q "^${package}/" ; then + deps="$deps src/include/$dep" + elif test -f "${dir}/$dep" ; then + deps="$deps ${dir}/$dep" + else + deps="$deps src/include-local/$dep" + fi + done + if test -n "$deps" ; then + echo "${dir}/${file}:${deps}" + fi + } + done +done + +for dir in src/* ; do + for file in $(ls -1 $dir | grep -- \\.c$) ; do + { + grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; + grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 + } | sort -u | { + deps=" ${dir}/$file" + while read dep ; do + if echo $dep | grep -q "^${package}/" ; then + deps="$deps src/include/$dep" + elif test -f "${dir}/$dep" ; then + deps="$deps ${dir}/$dep" + else + deps="$deps src/include-local/$dep" + fi + done + o=$(echo $file | sed s/\\.c$/.o/) + lo=$(echo $file | sed s/\\.c$/.lo/) + echo "${dir}/${o} ${dir}/${lo}:${deps}" + } + done +done +echo + +for dir in $(ls -1 src | grep -v ^include) ; do + for file in $(ls -1 src/$dir/deps-lib) ; do + deps= + libs= + while read dep ; do + if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then + libs="$libs $dep" + else + deps="$deps src/$dir/$dep" + fi + done < src/$dir/deps-lib/$file + echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)' + echo "lib${file}.a.xyzzy:$deps" + echo else + echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')" + echo endif + echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs" + echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')" + done + + for file in $(ls -1 src/$dir/deps-exe) ; do + deps= + libs= + while read dep ; do + if echo $dep | grep -q -- \\.o$ ; then + dep="src/$dir/$dep" + fi + if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then + libs="$libs $dep" + else + deps="$deps $dep" + fi + done < src/$dir/deps-exe/$file + echo "$file: EXTRA_LIBS :=$libs" + echo "$file: src/$dir/$file.o$deps" + done +done diff --git a/tools/install.sh b/tools/install.sh new file mode 100755 index 0000000..89f9428 --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +usage() { + echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2 + exit 1 +} + +mkdirp=false +symlink=false +mode=0755 + +while getopts Dlm: name ; do + case "$name" in + D) mkdirp=true ;; + l) symlink=true ;; + m) mode=$OPTARG ;; + ?) usage ;; + esac +done +shift $(($OPTIND - 1)) + +test "$#" -eq 2 || usage +src=$1 +dst=$2 +tmp="$dst.tmp.$$" + +case "$dst" in + */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;; +esac + +set -C +set -e + +if $mkdirp ; then + umask 022 + case "$2" in + */*) mkdir -p "${dst%/*}" ;; + esac +fi + +trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP + +umask 077 + +if $symlink ; then + ln -s "$src" "$tmp" +else + cat < "$1" > "$tmp" + chmod "$mode" "$tmp" +fi + +mv -f "$tmp" "$dst" +if test -d "$dst" ; then + rm -f "$dst/$(basename $tmp)" + if $symlink ; then + mkdir "$tmp" + ln -s "$src" "$tmp/$(basename $dst)" + mv -f "$tmp/$(basename $dst)" "${dst%/*}" + rmdir "$tmp" + else + echo "$0: $dst is a directory" 1>&2 + exit 1 + fi +fi -- cgit v1.3.1