From 21d51f7e0a639a3224ffc45dc3c06854decf1d45 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 30 Jan 2024 20:51:38 +0000 Subject: Initial commit Signed-off-by: Laurent Bercot --- .gitignore | 10 + AUTHORS | 2 + CONTRIBUTING | 5 + COPYING | 13 + DCO | 37 +++ INSTALL | 167 +++++++++++++ Makefile | 148 +++++++++++ NEWS | 6 + README | 23 ++ configure | 514 ++++++++++++++++++++++++++++++++++++++ doc/apaste.html | 114 +++++++++ doc/apastec.html | 88 +++++++ doc/apasted.html | 137 ++++++++++ doc/index.html | 110 ++++++++ doc/upgrade.html | 28 +++ package/deps-build | 2 + package/deps.mak | 16 ++ package/info | 4 + package/modes | 3 + package/targets.mak | 7 + patch-for-solaris | 21 ++ src/client/PROTOCOL.txt | 19 ++ src/client/apaste.c | 101 ++++++++ src/client/apastec.c | 155 ++++++++++++ src/client/apastec.h | 17 ++ src/client/deps-exe/apaste | 1 + src/client/deps-exe/apastec | 4 + src/client/send_file.c | 93 +++++++ src/include-local/apaste-common.h | 9 + src/server/apasted.c | 339 +++++++++++++++++++++++++ src/server/deps-exe/apasted | 3 + tools/gen-deps.sh | 100 ++++++++ tools/install.sh | 69 +++++ 33 files changed, 2365 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/apaste.html create mode 100644 doc/apastec.html create mode 100644 doc/apasted.html create mode 100644 doc/index.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 100755 patch-for-solaris create mode 100644 src/client/PROTOCOL.txt create mode 100644 src/client/apaste.c create mode 100644 src/client/apastec.c create mode 100644 src/client/apastec.h create mode 100644 src/client/deps-exe/apaste create mode 100644 src/client/deps-exe/apastec create mode 100644 src/client/send_file.c create mode 100644 src/include-local/apaste-common.h create mode 100644 src/server/apasted.c create mode 100644 src/server/deps-exe/apasted 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..5c3c565 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.o +*.a +*.lo +*.so +*.so.* +/config.mak +/src/include/apaste/config.h +/apaste +/apastec +/apasted 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..b747199 --- /dev/null +++ b/COPYING @@ -0,0 +1,13 @@ +Copyright (c) 2024 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..4765a67 --- /dev/null +++ b/INSTALL @@ -0,0 +1,167 @@ +Build Instructions +------------------ + +* Requirements + ------------ + + - A POSIX-compliant C development environment + - GNU make version 3.81 or later + - skalibs version 2.14.1.1 or later: https://skarnet.org/software/skalibs/ + - s6-networking version 2.7.0.2 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 /usr/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..b82361b --- /dev/null +++ b/Makefile @@ -0,0 +1,148 @@ +# +# 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) $(EXTRA_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) $(EXTRA_INCLUDES:src/include/%.h=$(DESTDIR)$(includedir)/%.h) + +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 apaste. diff --git a/configure b/configure new file mode 100755 index 0000000..6fa974d --- /dev/null +++ b/configure @@ -0,0 +1,514 @@ +#!/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= + +server=adelielinux.xyz +port=9999 +tlsport=9997 +cadir=/etc/ssl/certs +deftls=false +tmpdir=/tmp + +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#*=} ;; + --with-default-server=*) server=${arg#*=} ;; + --with-default-port=*) port=${arg#*=} ;; + --with-default-tlsport=*) tlsport=${arg#*=} ;; + --with-default-cadir=*) cadir=${arg#*=} ;; + --with-default-tls|--with-default-tls=yes) deftls=true ;; + --without-default-tls|--with-default-tls=no) deftls=false ;; + --with-tmpdir=*) tmpdir=${arg#*=} ;; + -* ) echo "$0: unknown option $arg" ;; + *=*) eval "${arg%%=*}=\${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=${DESTDIR}${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${DESTDIR}${sproot}${dep}/include" + vpaths="$vpaths ${DESTDIR}${sproot}${dep}/library" + addlibspath="$addlibspath -L${DESTDIR}${sproot}${dep}/library" + vpathd="$vpathd ${DESTDIR}${sproot}${dep}/library.so" + addlibdpath="$addlibdpath -L${DESTDIR}${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/apaste.html b/doc/apaste.html new file mode 100644 index 0000000..34f66d3 --- /dev/null +++ b/doc/apaste.html @@ -0,0 +1,114 @@ + + + + + + apaste: the apaste program + + + + + + +

+apaste
+Software
+skarnet.org +

+ +

The apaste program

+ +

+ apaste is a program that reads one or more files, or its +standard input, and sends the data to an apasted +server. +

+ +

Interface

+ +
+     apaste [ -S | -s ] [ -C cadir ] [ -d server[:port] ] [ -r rtimeout ] [ -w wtimeout ] file...
+
+ +
    +
  • apaste connects to a remote server via a plaintext or TLS-secured +connection, expecting to find an apasted server at the +other end.
  • +
  • For every file given as argument, it sends the contents of file +over the network. If file is - (dash), then stdout is transmitted +until EOF.
  • +
  • The server answers with a blob of six printable characters, named a slug. +Depending on the server configuration, it may embed the slug in a complete URL, for +easy copy-paste into a browser; or it may embed it in another way.
  • +
  • apaste prints the slug to its stdout, then exits 0.
  • +
+ +

Exit codes

+ +
+
0
Success. The data has been recorded by the server and available in +some way as indicated by the slug.
+
100
Bad usage. apaste was run in an incorrect way.
+
111
System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. +
+ +

Options

+ +
+
-S
+
Normal, plain text connection to the server, even if the built-in default +is TLS. The built-in default can be changed via the --with-default-tls +or --without-default-tls options to configure.
+ +
-s
+
TLS connection to the server, even if the built-in default +is plain text. The built-in default can be changed via the --with-default-tls +or --without-default-tls options to configure.
+ +
-C cadir
+
When using a TLS connection, use cadir as the directory +containing the hashed names of the trust anchor certificates +(used for verifying the server's certificate chain). The built-in default +can be changed via the --with-default-cadir option to configure.
+ +
-d server[:port]
+
Connect to server server, port port. The built-in defaults +can be changed via the --with-default-server, --with-default-port, +and --with-default-tlsport options to configure.
+ +
-r rtimeout
+
If the server isn't answering with a slug within rtimeout +milliseconds, give up. The default is 0, meaning infinite: apaste will +wait forever for a server reply if necessary.
+ +
-w wtimeout
+
If the server hasn't accepted all the data within wtimeout +milliseconds, give up. The default is 0, meaning infinite: apaste will +take as much time as it needs to send its data.
+
+ +

Example usage

+ +
    +
  • $ echo Blah blah. | apaste -
  • +
  • # apaste /etc/shadow (Just kidding. Don't do that.)
  • +
+ +

Notes

+ +
    +
  • apaste is only a wrapper around +s6-tcpclient +(for plain connections) or +s6-tlsclient +(for TLS-tunneled connections), and +apastec that is the real client. The point of apaste +is to provide a short command line with good compiled-in defaults; make sure +your defaults are correct at configure time when building the apaste package.
  • +
  • -, i.e. stdin, cannot be mentioned several times as an argument. It +can be transmitted with other files, but cannot be duplicated.
  • +
+ + + diff --git a/doc/apastec.html b/doc/apastec.html new file mode 100644 index 0000000..6711f3f --- /dev/null +++ b/doc/apastec.html @@ -0,0 +1,88 @@ + + + + + + apaste: the apastec program + + + + + + +

+apaste
+Software
+skarnet.org +

+ +

The apastec program

+ +

+ apastec is a program that reads one or more files, or its +standard input, and sends them to a preopened file descriptor. +

+ +

Interface

+ +
+     apastec [ -r rtimeout ] [ -w wtimeout ] file...
+
+ +
    +
  • apastec expects to have, in addition to standard file descriptors 0, 1 and 2, +its file descriptors 6 and 7 open and connected to a remote +apasted server.
  • +
  • For every file given as argument, it sends the contents of file +over the network. If file is - (dash), then stdout is transmitted +until EOF.
  • +
  • The server answers with a blob of six printable characters, named a slug. +Depending on the server configuration, it may embed the slug in a complete URL, for +easy copy-paste into a browser; or it may embed it in another way.
  • +
  • apastec prints the slug to its stdout, then exits 0.
  • +
+ +

Exit codes

+ +
+
0
Success. The data has been recorded by the server and available in +some way as indicated by the slug.
+
100
Bad usage. apaste was run in an incorrect way.
+
111
System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. +
+ +

Options

+ +
+
-r rtimeout
+
If the server isn't answering with a slug within rtimeout +milliseconds, give up. The default is 0, meaning infinite: apastec will +wait forever for a server reply if necessary.
+ +
-w wtimeout
+
If the server hasn't accepted all the data within wtimeout +milliseconds, give up. The default is 0, meaning infinite: apastec will +take as much time as it needs to send its data.
+
+ +

Typical usage

+ +

+ apastec isn't meant to be used directly. It is meant to be invoked as +part of a command line crafted by the apaste +command, where programs from the +s6-networking package +establish the connection to the server, then exec into apastec to read +the user's data and transmit them with the apaste protocol. +

+ +

Notes

+ +
    +
  • -, i.e. stdin, cannot be mentioned several times as an argument. It +can be transmitted with other files, but cannot be duplicated.
  • +
+ + + diff --git a/doc/apasted.html b/doc/apasted.html new file mode 100644 index 0000000..98ec51d --- /dev/null +++ b/doc/apasted.html @@ -0,0 +1,137 @@ + + + + + + apaste: the apasted program + + + + + + +

+apaste
+Software
+skarnet.org +

+ +

The apasted program

+ +

+ apasted is the server-side program for the apaste package. It +expects its stdin and stdout to be connected to the network, having being +contacted by an apastec client. It reads a +series of files transmitted by the client, stores it on the server, and +sends back a slug to the client, i.e. an identifier for the +stored files. +

+ +

Interface

+ +
+     apasted [ -r rtimeout ] [ -w wtimeout ] [ -d rootdir ] [ -p prefix ] [ -m maxfiles ]
+
+ +
    +
  • apasted reads data on its stdin, expecting the protocol spoken by the +apastec client, containing one or more files.
  • +
  • It creates a subdirectory subdir in its working directory, +and stores the files it receives under it. +
      +
    • If it only receives one file, it stores it in subdir/index.txt.
    • +
    • If it receives two or more files, it stores each file file as +subdir/file.txt, and creates a +subdir/index.html file with hyperlinks to every file in subdir.
    • +
  • +
  • It sends the subdir name back to the client, as a slug.
  • +
  • It exits 0
  • +
+ +

Exit codes

+ +
+
0
Success.
+
1
Protocol error. The client sent incorrectly formatted data.
+
100
Bad usage. apasted was run in an incorrect way.
+
111
System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. +
+ +

Options

+ +
+
-r rtimeout
+
If the client hasn't transmitted all its data within rtimeout +milliseconds, give up. The default is 0, meaning infinite: apasted will +wait forever for client data if necessary.
+ +
-w wtimeout
+
If apasted fails to send the slug to the client within wtimeout +milliseconds, give up. The default is 0, meaning infinite: apasted will +take as much time as it needs to send its answer.
+ +
-d rootdir
+
Switch to rootdir and store files there. The default is +apasted's working directory.
+ +
-p prefix
+
When sending a slug to the client, prefix subdir with prefix, +and append a slash at the end. This is useful when apasted writes its files to +a web server's document hierarchy, which is the intended case. If prefix +is the URL of apasted's base directory, then the slug can directly be used as a +URL to access the client's files.
+ +
-m maxfiles
+
Accept a maximum of maxfiles files at a time from the client. +The default is 0, meaning unlimited: the client can send as many files as it +wants and apasted will still store them if it is possible.
+
+ +

Typical usage

+ +
    +
  • apasted is meant to be run under a super-server accepting client connections. +Run it under inetd or +s6-tcpserver +for plaintext connections, and under +s6-tlsserver +for TLS-tunneled connections.
  • +
  • To publish the data received and stored by apasted, the simplest way is +to have a web server running and serving the hierarchy of apasted files. Use the +-p option on the apasted command line to make sure the client receives +a full URL to its files.
  • +
+ +

Caveats

+ +
    +
  • apaste is a push protocol: the client sends data to be stored on +the server. As such, it is very easy to abuse, and caution should be taken when +running an apasted server: +
      +
    • If possible, have quotas on the filesystem hosting the apasted storage area
    • +
    • Use the -m option to avoid trivial inode exhaustion attacks
    • +
    • Use your super-server's options to mitigate client patterns of abuse, log and +block the IPs of problematic clients
    • +
    • Run scripts that regularly delete old subdirs (and their contents) +in the apasted storage area.
    • +
    • Be aware, and warn your users, that a pastebin is a service to the community, +and that abusing the service is the best and quickest way to make it go away.
    • +
  • +
+ +

Notes

+ +
    +
  • apasted will store a file named file as file.txt so that a +web server can always serve it as plain text. apaste is not meant to send binary +files of an arbitrary MIME type.
  • +
  • A unique file is stored as slug/index.txt; if apasted is +run with -p http://example.com/ then the apaste client, on success, +will print http://example.com/slug/. Make sure that your web server can +automatically interpret that URL as http://example.com/slug/index.txt.
  • +
+ + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..6697333 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,110 @@ + + + + + + apaste - a small command-line pastebin + + + + + + +

+Software
+skarnet.org +

+ +

apaste

+ +

What is it ?

+ +

+ apaste is a small command-line pastebin, to share terminal output +by pushing it to a server, so it can be made public via the Web or some +other protocol. +

+ +
+ +

Installation

+ +

Requirements

+ +
    +
  • A POSIX-compliant system with a standard C development environment
  • +
  • GNU make, version 3.81 or later
  • +
  • skalibs version +2.14.1.1 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-networking version +2.7.0.2 or later. It's a build-time and run-time requirement: it's the layer +that provides the network connection.
  • +
+ +

Licensing

+ +

+ apaste is free software. It is available under the +ISC license. +

+ +

Download

+ +
    +
  • The current released version of apaste is +0.0.1.0.
  • +
  • You can checkout a copy of the +apaste +git repository: +
     git clone git://git.skarnet.org/apaste 
  • +
  • There's also a +GitHub mirror +of the apaste git repository.
  • +
+ +

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 apaste and the current one.
  • +
+ +
+ +

Reference

+ +

Commands

+ + + +

Related resources

+ +
    +
  • apaste is discussed on the +skaware mailing-list.
  • +
+ +

Similar work

+ +
    +
  • fiche is also +a small command-line pastebin utility.
  • +
  • tpaste and +sprunge are similar utilities, +one written in lua, the other in Python.
  • +
+ + + diff --git a/doc/upgrade.html b/doc/upgrade.html new file mode 100644 index 0000000..c8650e5 --- /dev/null +++ b/doc/upgrade.html @@ -0,0 +1,28 @@ + + + + + + apaste: how to upgrade + + + + + + +

+apaste
+Software
+skarnet.org +

+ +

What has changed in apaste

+ +

in 0.0.1.0

+ +
    +
  • Initial release.
  • +
+ + + diff --git a/package/deps-build b/package/deps-build new file mode 100644 index 0000000..c4bd95c --- /dev/null +++ b/package/deps-build @@ -0,0 +1,2 @@ +/package/prog/skalibs +/package/net/s6-networking diff --git a/package/deps.mak b/package/deps.mak new file mode 100644 index 0000000..3f6192a --- /dev/null +++ b/package/deps.mak @@ -0,0 +1,16 @@ +# +# This file has been generated by tools/gen-deps.sh +# + +src/client/apaste.o src/client/apaste.lo: src/client/apaste.c src/include/apaste/config.h +src/client/apastec.o src/client/apastec.lo: src/client/apastec.c src/include-local/apaste-common.h src/include/apaste/config.h src/client/apastec.h +src/client/send_file.o src/client/send_file.lo: src/client/send_file.c +src/server/apasted.o src/server/apasted.lo: src/server/apasted.c src/include-local/apaste-common.h src/include/apaste/config.h + +apaste: EXTRA_LIBS := -lskarnet +apaste: src/client/apaste.o +apastec: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} +apastec: src/client/apastec.o src/client/send_file.o +apasted: EXTRA_LIBS := -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} +apasted: src/server/apasted.o +INTERNAL_LIBS := diff --git a/package/info b/package/info new file mode 100644 index 0000000..333079b --- /dev/null +++ b/package/info @@ -0,0 +1,4 @@ +package=apaste +version=0.0.1.0 +category=web +package_macro_name=APASTE diff --git a/package/modes b/package/modes new file mode 100644 index 0000000..4e5f807 --- /dev/null +++ b/package/modes @@ -0,0 +1,3 @@ +apaste 0755 +apastec 0755 +apasted 0755 diff --git a/package/targets.mak b/package/targets.mak new file mode 100644 index 0000000..1c4f30e --- /dev/null +++ b/package/targets.mak @@ -0,0 +1,7 @@ +BIN_TARGETS := \ +apaste \ +apastec \ +apasted + +LIBEXEC_TARGETS := + diff --git a/patch-for-solaris b/patch-for-solaris new file mode 100755 index 0000000..2d1296b --- /dev/null +++ b/patch-for-solaris @@ -0,0 +1,21 @@ +#!/usr/xpg4/bin/sh + +patchit () { + echo '#!/usr/xpg4/bin/sh' > $1.tmp + tail -n +2 $1 >> $1.tmp + mv -f $1.tmp $1 + chmod 755 $1 +} + +# Solaris doesn't understand POSIX.1-2008 either. +sed -e 's/XOPEN_SOURCE=700/XOPEN_SOURCE=600/' < configure > configure.tmp +mv -f configure.tmp configure + +patchit ./configure +patchit ./tools/install.sh +patchit ./tools/gen-deps.sh + +echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp +echo >> Makefile.tmp +cat Makefile >> Makefile.tmp +mv -f Makefile.tmp Makefile diff --git a/src/client/PROTOCOL.txt b/src/client/PROTOCOL.txt new file mode 100644 index 0000000..6e828ca --- /dev/null +++ b/src/client/PROTOCOL.txt @@ -0,0 +1,19 @@ + +apastec: + +banner \n +nfiles (uint32) \n +{ + namelength (uint16) \n + name (namelength) \n + filelength (uint64) \n + file (filelength) \n +} +banner \n + + +apasted: + +banner \n +slug \n +banner \n diff --git a/src/client/apaste.c b/src/client/apaste.c new file mode 100644 index 0000000..1d2a739 --- /dev/null +++ b/src/client/apaste.c @@ -0,0 +1,101 @@ +/* ISC license. */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define USAGE "apaste [ -S | -s ] [ -C cadir ] [ -d server[:port] ] [ -r rtimeout ] [ -w wtimeout ] file..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char *const *argv) +{ + char const *cadir = APASTE_DEFAULT_CADIR ; + char const *server = APASTE_DEFAULT_SERVER ; + int dotls = APASTE_DEFAULT_TLS ; + uint32_t rt = 0 ; + uint32_t wt = 0 ; + uint16_t port = 0 ; + PROG = "apaste" ; + + { + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, (char const *const *)argv, "SsC:d:r:w:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : dotls = 0 ; break ; + case 's' : dotls = 1 ; break ; + case 'C' : cadir = l.arg ; break ; + case 'd' : + { + char *colon = strchr(l.arg, ':') ; + server = l.arg ; + if (colon) + { + *colon = 0 ; + if (!uint160_scan(colon + 1, &port)) dieusage() ; + } + break ; + } + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) dieusage() ; + if (!port) port = dotls ? APASTE_DEFAULT_TLSPORT : APASTE_DEFAULT_PORT ; + { + char const *newargv[12 + argc] ; + unsigned int m = 0 ; + char fmtr[UINT32_FMT] ; + char fmtw[UINT32_FMT] ; + char fmtp[UINT16_FMT] ; + + fmtp[uint16_fmt(fmtp, port)] = 0 ; + + newargv[m++] = dotls ? S6_NETWORKING_EXTBINPREFIX "s6-tlsclient" : S6_NETWORKING_EXTBINPREFIX "s6-tcpclient" ; + newargv[m++] = "-N" ; + newargv[m++] = "--" ; + newargv[m++] = server ; + newargv[m++] = fmtp ; + newargv[m++] = APASTE_BINPREFIX "apastec" ; + if (rt) + { + fmtr[uint32_fmt(fmtr, rt)] = 0 ; + newargv[m++] = "-r" ; + newargv[m++] = fmtr ; + } + if (rt) + { + fmtw[uint32_fmt(fmtw, wt)] = 0 ; + newargv[m++] = "-w" ; + newargv[m++] = fmtw ; + } + newargv[m++] = "--" ; + while (argc--) newargv[m++] = *argv++ ; + newargv[m++] = 0 ; + + if (dotls) + { + size_t len = strlen(cadir) ; + char modif[7 + len] ; + memcpy(modif, "CADIR=", 6) ; + memcpy(modif + 6, cadir, len + 1) ; + xmexec_n(newargv, modif, len + 7, 1) ; + } + else xexec(newargv) ; + } +} diff --git a/src/client/apastec.c b/src/client/apastec.c new file mode 100644 index 0000000..3237ceb --- /dev/null +++ b/src/client/apastec.c @@ -0,0 +1,155 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "apaste-common.h" +#include "apastec.h" + +#define USAGE "apastec [ -r rtimeout ] [ -w wtimeout ] file..." +#define dieusage() strerr_dieusage(100, USAGE) + +static void apaste_send (buffer *b, char const *file, tain const *deadline) +{ + int fd ; + struct stat st ; + size_t len = strlen(file) ; + if (!len) strerr_dief2x(100, "empty file", " names are invalid") ; + if (len > UINT16_MAX) strerr_dief2x(100, "file name too long: ", file) ; + if (len == 1 && file[0] == '-') + { + char tmp[sizeof(APASTE_TMPDIR) + 14] = APASTE_TMPDIR "/apaste:XXXXXX" ; + fd = mkstemp(tmp) ; + if (fd == -1) strerr_diefu2sys(111, "mkstemp ", tmp) ; + unlink_void(tmp) ; + if (fd_cat(0, fd) == -1) strerr_diefu2sys(111, "copy stdin to ", tmp) ; + if (lseek(fd, 0, SEEK_SET) == -1) strerr_diefu1sys(111, "lseek") ; + ndelay_on(fd) ; + } + else + { + if (file[len-1] == '/') strerr_dief2x(100, "directory", " names are invalid") ; + fd = open_read(file) ; + if (fd == -1) strerr_diefu2sys(111, "open ", file) ; + } + + if (fstat(fd, &st) == -1) strerr_diefu2sys(111, "stat ", file) ; + if (!S_ISREG(st.st_mode)) strerr_dief3x(100, "file ", file, " is not a regular file") ; + { + char fmt[UINT64_FMT] ; + size_t m = uint16_fmt(fmt, len) ; + fmt[m++] = '\n' ; + if (buffer_timed_put_g(b, fmt, m, deadline) < m + || buffer_timed_put_g(b, file, len, deadline) < len + || buffer_timed_put_g(b, "\n", 1, deadline) < 1) + strerr_diefu1sys(111, "write to server") ; + m = uint64_fmt(fmt, st.st_size) ; + fmt[m++] = '\n' ; + if (buffer_timed_put_g(b, fmt, m, deadline) < m) + strerr_diefu1sys(111, "write to server") ; + } + send_file_g(b, fd, st.st_size, file, deadline) ; + fd_close(fd) ; + if (buffer_timed_put_g(b, "\n", 1, deadline) < 1) + strerr_diefu1sys(111, "write to server") ; +} + +int main (int argc, char const *const *argv) +{ + tain rtto = TAIN_INFINITE_RELATIVE, wtto = TAIN_INFINITE_RELATIVE ; + tain deadline ; + PROG = "apastec" ; + { + uint32_t rt = 0, wt = 0 ; + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "r:w:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (rt) tain_from_millisecs(&rtto, rt) ; + if (wt) tain_from_millisecs(&rtto, wt) ; + } + if (!argc) dieusage() ; + if (argc > UINT32_MAX) strerr_dief1x(100, "too many arguments") ; + + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; + tain_now_set_stopwatch_g() ; + tain_add_g(&deadline, &wtto) ; + + { + char buf[BUFFER_OUTSIZE] ; + buffer b = BUFFER_INIT(&buffer_write, 7, buf, BUFFER_OUTSIZE) ; + buffer_putnoflush(&b, APASTEC_BANNER "\n", sizeof(APASTEC_BANNER)) ; + { + char fmt[UINT32_FMT] ; + size_t m = uint32_fmt(fmt, argc) ; + fmt[m++] = '\n' ; + buffer_putnoflush(&b, fmt, m) ; + } + { + int gotstdin = 0 ; + for (unsigned int i = 0 ; i < argc ; i++) if (argv[i][0] == '-' && !argv[i][1]) + { + if (gotstdin) strerr_dief1x(100, "stdin specified more than once") ; + gotstdin = 1 ; + } + } + for (unsigned int i = 0 ; i < argc ; i++) apaste_send(&b, argv[i], &deadline) ; + if (buffer_timed_put_g(&b, APASTEC_BANNER "\n", sizeof(APASTEC_BANNER), &deadline) < sizeof(APASTEC_BANNER) + || !buffer_timed_flush_g(&b, &deadline)) + strerr_diefu1sys(111, "write to apaste server") ; + } + + fd_shutdown(7, 1) ; + fd_close(7) ; + tain_add_g(&deadline, &rtto) ; + + { + char buf[BUFFER_INSIZE] ; + char banner[256] ; + char slug[256] ; + buffer b = BUFFER_INIT(&buffer_read, 6, buf, BUFFER_INSIZE) ; + size_t w = 0, sluglen = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + if (w != sizeof(APASTED_BANNER) || memcmp(banner, APASTED_BANNER, w-1)) + strerr_dief1x(1, "server returned invalid data") ; + if (sanitize_read(timed_getlnmax_g(&b, slug, 256, &sluglen, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + if (w != sizeof(APASTED_BANNER) || memcmp(banner, APASTED_BANNER, w-1)) + strerr_dief1x(1, "server returned invalid data") ; + if (buffer_putflush(buffer_1small, slug, sluglen) == -1) + strerr_diefu1sys(111, "write to stdout") ; + } + + return 0 ; +} diff --git a/src/client/apastec.h b/src/client/apastec.h new file mode 100644 index 0000000..84ab242 --- /dev/null +++ b/src/client/apastec.h @@ -0,0 +1,17 @@ +/* ISC license. */ + +#ifndef APASTEC_H +#define APASTEC_H + +#include + +#include +#include + + +/* send_file.c */ + +extern void send_file (buffer *, int, off_t, char const *, tain const *, tain *) ; +#define send_file_g(b, fd, size, file, deadline) send_file(b, fd, size, file, (deadline), &STAMP) + +#endif diff --git a/src/client/deps-exe/apaste b/src/client/deps-exe/apaste new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/client/deps-exe/apaste @@ -0,0 +1 @@ +-lskarnet diff --git a/src/client/deps-exe/apastec b/src/client/deps-exe/apastec new file mode 100644 index 0000000..1e0ab64 --- /dev/null +++ b/src/client/deps-exe/apastec @@ -0,0 +1,4 @@ +send_file.o +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/src/client/send_file.c b/src/client/send_file.c new file mode 100644 index 0000000..4da8412 --- /dev/null +++ b/src/client/send_file.c @@ -0,0 +1,93 @@ +/* ISC license. */ + +#include + +#ifdef SKALIBS_HASSENDFILE + +#include +#include +#include + +#include +#include +#include +#include + +struct sendfile_s +{ + int fd ; + buffer *out ; + off_t pos ; + uint64_t n ; +} ; + +static int s_getfd (void *p) +{ + struct sendfile_s *sf = p ; + return buffer_fd(sf->out) ; +} + +static int s_isnonempty (void *p) +{ + struct sendfile_s *sf = p ; + return !!sf->n ; +} + +static int s_flush (void *p) +{ + struct sendfile_s *sf = p ; + while (sf->n) + { + ssize_t r = sendfile(buffer_fd(sf->out), sf->fd, &sf->pos, sf->n > SSIZE_MAX ? SSIZE_MAX : sf->n) ; + if (r == -1) return 0 ; + sf->n -= r ; + } + return 1 ; +} + +void send_file (buffer *b, int fd, off_t size, char const *fn, tain const *deadline, tain *stamp) +{ + struct sendfile_s sf = { .fd = fd, .out = b, .pos = 0, .n = size } ; + if (!buffer_timed_flush(b, deadline, stamp)) + strerr_diefu1sys(111, "write to network") ; + if (!timed_flush(&sf, &s_getfd, &s_isnonempty, &s_flush, deadline, stamp)) + strerr_diefu3sys(111, "sendfile ", fn, " to network") ; +} + +#else + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void send_file (buffer *b, int fd, uint64_t n, char const *fn, tain const *deadline, tain *stamp) +{ + struct iovec v[2] ; + ssize_t r ; + if (!n) goto flushit ; + fillit: + buffer_wpeek(b, v) ; + r = allreadv(fd, v, 2) ; + if (r == -1) strerr_diefu2sys(111, "read from ", fn) ; + if (!r) strerr_diefu3x(111, "send ", fn, ": file was truncated") ; + if (r > n) + { + r = n ; + strerr_warnw2x("sending elongated file: ", fn) ; + } + buffer_wseek(b, r) ; + n -= r ; + flushit: + if (!buffer_timed_flush(b, deadline, stamp)) + strerr_diefu1sys(111, "write to network") ; + if (n) goto fillit ; +} + +#endif diff --git a/src/include-local/apaste-common.h b/src/include-local/apaste-common.h new file mode 100644 index 0000000..8a680d9 --- /dev/null +++ b/src/include-local/apaste-common.h @@ -0,0 +1,9 @@ +/* ISC license. */ + +#ifndef APASTE_COMMON_H +#define APASTE_COMMON_H + +#define APASTEC_BANNER "apastec protocol v1" +#define APASTED_BANNER "apasted protocol v1" + +#endif diff --git a/src/server/apasted.c b/src/server/apasted.c new file mode 100644 index 0000000..b338154 --- /dev/null +++ b/src/server/apasted.c @@ -0,0 +1,339 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "apaste-common.h" + +#define USAGE "apasted [ -r rtimeout ] [ -w wtimeout ] [ -d rootdir ] [ -p prefix ] [ -m maxfiles ]" +#define dieusage() strerr_dieusage(100, USAGE) + +#define FORBIDDEN " \t\r\n\"<>&;" + +#define INDEXSTART "\ +\n\ + \n\ + \n\ + \n\ + \n\ + apaste results\n\ + \n\ + \n\ +\n\ +

apaste results

\n\ +
    \n" + +static void cleanup (char const *dir) +{ + int e = errno ; + rm_rf(dir) ; + errno = e ; +} + +static void prepare_index (buffer *ib, char const *dir, char *buf, size_t buflen) +{ + int fd ; + size_t dirlen = strlen(dir) ; + char fn[dirlen + 12] ; + memcpy(fn, dir, dirlen) ; + memcpy(fn + dirlen, "/index.html", 12) ; + fd = open_create(fn) ; + if (fd == -1) + { + cleanup(dir) ; + strerr_diefu3sys(111, "open ", dir, "/index.html for writing") ; + } + buffer_init(ib, &buffer_write, fd, buf, buflen) ; + if (buffer_puts(ib, INDEXSTART) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "prepare index for ", dir) ; + } +} + +static inline void add_index_entry (char const *dir, buffer *ib, char const *name, uint64_t filelen) +{ + char fmt[UINT64_FMT] ; + size_t m = uint64_fmt(fmt, filelen) ; + if (buffer_puts(ib, "
  • ") == -1 + || buffer_puts(ib, name) == -1 + || buffer_puts(ib, " (") == -1 + || buffer_put(ib, fmt, m) == -1 + || buffer_puts(ib, " bytes)
  • \n") == -1) + { + cleanup(dir) ; + strerr_diefu5sys(111, "add ", name, " to ", dir, "/index.html") ; + } +} + +static inline void finish_index (buffer *ib, char const *dir) +{ + if (buffer_putsflush(ib, "
\n\n\n") == -1 + || fsync(buffer_fd(ib)) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "finish index for ", dir) ; + } + fd_close(buffer_fd(ib)) ; +} + +static inline void recv_one_file (char const *dir, char const *fn, buffer *b, int fd, uint64_t n, tain const *deadline) +{ + struct iovec v[2] ; + size_t len ; + while (n) + { + unsigned int j = 2 ; + if (buffer_len(b) < n) + { + if (sanitize_read(buffer_timed_fill_g(b, deadline)) <= 0) + { + cleanup(dir) ; + _exit(1) ; + } + } + buffer_rpeek(b, v) ; + len = siovec_len(v, 2) ; + if (len > n) + { + j = siovec_trunc(v, 2, n) ; + len = n ; + } + if (allwritev(fd, v, j) < len) + { + cleanup(dir) ; + strerr_diefu2sys(111, "write to ", fn) ; + } + buffer_rseek(b, len) ; + n -= len ; + } +} + +static inline size_t add_unique (stralloc *sa, size_t *indices, uint32_t n, char const *bname) +{ + size_t blen = strlen(bname) ; + size_t pos = sa->len ; + static uint32_t suffix = 0 ; + if (!stralloc_readyplus(sa, blen + UINT32_FMT + 2)) return 0 ; + memcpy(sa->s + pos, bname, blen + 1) ; + for (;;) + { + uint32_t i = 0 ; + for (; i < n ; i++) if (!strcmp(sa->s + indices[i], sa->s + pos)) break ; + if (i == n) break ; + sa->s[pos + blen] = '.' ; + sa->s[pos + blen + 1 + uint32_fmt(sa->s + pos + blen + 1, suffix++)] = 0 ; + } + + blen = strlen(sa->s + pos) ; + indices[n] = sa->len ; + sa->len += blen + 1 ; + return blen ; +} + +static void read_one_file (char const *dir, buffer *b, buffer *ib, stralloc *sa, size_t *indices, uint32_t n, tain const *deadline) +{ + uint64_t filelen ; + size_t bnamelen ; + uint16_t namelen ; + + { + size_t w = 0 ; + size_t m ; + char fmt[UINT16_FMT] ; + if (sanitize_read(timed_getlnmax_g(b, fmt, UINT16_FMT, &w, '\n', deadline)) <= 0) goto err ; + m = uint16_scan(fmt, &namelen) ; + if (!m || m+1 != w || fmt[m] != '\n') goto err ; + } + + { + size_t w = 0 ; + char *bname ; + char name[namelen + 1] ; + if (sanitize_read(timed_getlnmax_g(b, name, namelen + 1, &w, '\n', deadline)) <= 0) goto err ; + if (!w || w != namelen + 1 || name[namelen] != '\n') goto err ; + name[namelen] = 0 ; + bname = strrchr(name, '/') ; + if (bname) bname++ ; else bname = name ; + if (!*bname) goto err ; + + if (ib) /* sanitize the filename for inclusion in index.html */ + { + size_t blen = strlen(bname) ; + if (byte_in(bname, blen, FORBIDDEN, sizeof(FORBIDDEN)) != blen) goto err ; + bnamelen = add_unique(sa, indices, n, bname) ; + if (!bnamelen) + { + cleanup(dir) ; + strerr_diefu3sys(111, "make ", bname, " unique") ; + } + } + else bnamelen = 5 ; + } + + { + size_t w = 0 ; + size_t m ; + char fmt[UINT64_FMT] ; + if (sanitize_read(timed_getlnmax_g(b, fmt, UINT64_FMT, &w, '\n', deadline)) <= 0) goto err ; + m = uint64_scan(fmt, &filelen) ; + if (!m || m+1 != w || fmt[m] != '\n') goto err ; + } + + { + int fd ; + size_t dirlen = strlen(dir) ; + char fn[dirlen + bnamelen + 6] ; + memcpy(fn, dir, dirlen) ; + fn[dirlen] = '/' ; + memcpy(fn + dirlen + 1, ib ? sa->s + indices[n] : "index", bnamelen) ; + memcpy(fn + dirlen + 1 + bnamelen, ".txt", 5) ; + fd = open_create(fn) ; + if (fd == -1) + { + cleanup(dir) ; + strerr_diefu3sys(111, "open ", fn, " for writing") ; + } + recv_one_file(dir, fn, b, fd, filelen, deadline) ; + if (fsync(fd) == -1) + { + cleanup(dir) ; + strerr_diefu2sys(111, "fsync ", fn) ; + } + fd_close(fd) ; + } + + { + char c ; + if (sanitize_read(buffer_timed_get_g(b, &c, 1, deadline)) != 1) goto err ; + if (c != '\n') goto err ; + } + + if (ib) add_index_entry(dir, ib, sa->s + indices[n], filelen) ; + return ; + + err: + cleanup(dir) ; + _exit(1) ; +} + +int main (int argc, char const *const *argv) +{ + char const *prefix = "" ; + tain rtto = TAIN_INFINITE_RELATIVE, wtto = TAIN_INFINITE_RELATIVE ; + tain deadline ; + uint32_t maxfiles = 0 ; + uint32_t n ; + char buf[4097] ; + char dir[7] = "XXXXXX" ; + buffer b = BUFFER_INIT(&buffer_read, 0, buf, 4097) ; + PROG = "apasted" ; + { + char const *rootdir = 0 ; + uint32_t rt = 0, wt = 0 ; + subgetopt l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "r:w:d:p:m:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'r' : if (!uint320_scan(l.arg, &rt)) dieusage() ; break ; + case 'w' : if (!uint320_scan(l.arg, &wt)) dieusage() ; break ; + case 'd' : rootdir = l.arg ; break ; + case 'p' : prefix = l.arg ; break ; + case 'm' : if (!uint320_scan(l.arg, &maxfiles)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (rt) tain_from_millisecs(&rtto, rt) ; + if (wt) tain_from_millisecs(&rtto, wt) ; + if (rootdir && chdir(rootdir) == -1) + strerr_diefu2sys(111, "chdir to ", rootdir) ; + if (strlen(prefix) > 4000) strerr_dief1x(100, "prefix too long") ; + } + + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; + tain_now_set_stopwatch_g() ; + tain_add_g(&deadline, &rtto) ; + + { + char banner[256] ; + size_t w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0) _exit(1) ; + if (w != sizeof(APASTEC_BANNER) || memcmp(banner, APASTEC_BANNER, w-1)) _exit(1) ; + } + + { + char fmt[UINT32_FMT] ; + size_t w = 0 ; + size_t m ; + if (sanitize_read(timed_getlnmax_g(&b, fmt, UINT32_FMT, &w, '\n', &deadline)) <= 0) + strerr_diefu1sys(111, "read from apaste server") ; + m = uint32_scan(fmt, &n) ; + if (!m || m+1 != w) _exit(1) ; + if (!n || (maxfiles && n > maxfiles)) _exit(1) ; + } + + if (!mkdtemp(dir)) strerr_diefu1sys(111, "mkdtemp") ; + if (n == 1) read_one_file(dir, &b, 0, 0, 0, 0, &deadline) ; + else + { + stralloc sa = STRALLOC_ZERO ; + size_t indices[n] ; + buffer ib ; + char ibuf[4096] ; + prepare_index(&ib, dir, ibuf, 4096) ; + for (uint32_t i = 0 ; i < n ; i++) read_one_file(dir, &b, &ib, &sa, indices, i, &deadline) ; + finish_index(&ib, dir) ; + } + + { + char banner[256] ; + size_t w = 0 ; + if (sanitize_read(timed_getlnmax_g(&b, banner, 256, &w, '\n', &deadline)) <= 0 + || w != sizeof(APASTEC_BANNER) + || memcmp(banner, APASTEC_BANNER, w-1)) goto err ; + } + + buffer_init(&b, &buffer_write, 1, buf, 4097) ; + buffer_putsnoflush(&b, APASTED_BANNER "\n") ; + if (prefix[0]) buffer_putsnoflush(&b, prefix) ; + buffer_putnoflush(&b, dir, 6) ; + if (!strncmp(prefix, "http", 4)) buffer_putnoflush(&b, "/", 1) ; + buffer_putsnoflush(&b, "\n" APASTED_BANNER "\n") ; + tain_add_g(&deadline, &wtto) ; + if (!buffer_timed_flush_g(&b, &deadline)) goto err ; + + return 0 ; + + err: + cleanup(dir) ; + return 1 ; +} diff --git a/src/server/deps-exe/apasted b/src/server/deps-exe/apasted new file mode 100644 index 0000000..720fe7d --- /dev/null +++ b/src/server/deps-exe/apasted @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh new file mode 100755 index 0000000..befe021 --- /dev/null +++ b/tools/gen-deps.sh @@ -0,0 +1,100 @@ +#!/bin/sh -e + +. package/info + +echo '#' +echo '# This file has been generated by tools/gen-deps.sh' +echo '#' +echo + +internal_libs= + +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 + if grep -E "^LIB_DEFS [+:]=" package/targets.mak | grep -qF "$file" ; then + echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs" + echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')" + else + internal_libs="$internal_libs lib${file}.a.xyzzy" + fi + 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 +echo "INTERNAL_LIBS :=$internal_libs" diff --git a/tools/install.sh b/tools/install.sh new file mode 100755 index 0000000..e96dd7b --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +usage() { + echo "usage: $0 [ -D ] [ -l ] [ -m mode ] [ -O owner:group ] src dst" 1>&2 + exit 1 +} + +mkdirp=false +symlink=false +mode=0755 +og= + +while getopts Dlm:O: name ; do + case "$name" in + D) mkdirp=true ;; + l) symlink=true ;; + m) mode=$OPTARG ;; + O) og=$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" + if test -n "$og" ; then + chown -- "$og" "$tmp" + fi + 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