diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2024-01-30 20:51:38 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska@appnovation.com> | 2024-01-30 20:51:38 +0000 |
| commit | 21d51f7e0a639a3224ffc45dc3c06854decf1d45 (patch) | |
| tree | 87c4a36f66510e79d7ec8315361bb8bbbb5767f5 | |
| download | apaste-21d51f7e0a639a3224ffc45dc3c06854decf1d45.tar.gz | |
Initial commit
Signed-off-by: Laurent Bercot <ska@appnovation.com>
| -rw-r--r-- | .gitignore | 10 | ||||
| -rw-r--r-- | AUTHORS | 2 | ||||
| -rw-r--r-- | CONTRIBUTING | 5 | ||||
| -rw-r--r-- | COPYING | 13 | ||||
| -rw-r--r-- | DCO | 37 | ||||
| -rw-r--r-- | INSTALL | 167 | ||||
| -rw-r--r-- | Makefile | 148 | ||||
| -rw-r--r-- | NEWS | 6 | ||||
| -rw-r--r-- | README | 23 | ||||
| -rwxr-xr-x | configure | 514 | ||||
| -rw-r--r-- | doc/apaste.html | 114 | ||||
| -rw-r--r-- | doc/apastec.html | 88 | ||||
| -rw-r--r-- | doc/apasted.html | 137 | ||||
| -rw-r--r-- | doc/index.html | 110 | ||||
| -rw-r--r-- | doc/upgrade.html | 28 | ||||
| -rw-r--r-- | package/deps-build | 2 | ||||
| -rw-r--r-- | package/deps.mak | 16 | ||||
| -rw-r--r-- | package/info | 4 | ||||
| -rw-r--r-- | package/modes | 3 | ||||
| -rw-r--r-- | package/targets.mak | 7 | ||||
| -rwxr-xr-x | patch-for-solaris | 21 | ||||
| -rw-r--r-- | src/client/PROTOCOL.txt | 19 | ||||
| -rw-r--r-- | src/client/apaste.c | 101 | ||||
| -rw-r--r-- | src/client/apastec.c | 155 | ||||
| -rw-r--r-- | src/client/apastec.h | 17 | ||||
| -rw-r--r-- | src/client/deps-exe/apaste | 1 | ||||
| -rw-r--r-- | src/client/deps-exe/apastec | 4 | ||||
| -rw-r--r-- | src/client/send_file.c | 93 | ||||
| -rw-r--r-- | src/include-local/apaste-common.h | 9 | ||||
| -rw-r--r-- | src/server/apasted.c | 339 | ||||
| -rw-r--r-- | src/server/deps-exe/apasted | 3 | ||||
| -rwxr-xr-x | tools/gen-deps.sh | 100 | ||||
| -rwxr-xr-x | tools/install.sh | 69 |
33 files changed, 2365 insertions, 0 deletions
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 @@ -0,0 +1,2 @@ +Main author: + Laurent Bercot <ska-skaware@skarnet.org> 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/ @@ -0,0 +1,13 @@ +Copyright (c) 2024 Laurent Bercot <ska-skaware@skarnet.org> + +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. @@ -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. @@ -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/$(<F) $@ + +$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M) + exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@ + +.PHONY: update global-links + +endif + +$(DESTDIR)$(dynlibdir)/lib%.so $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M): lib%.so.xyzzy + $(INSTALL) -D -m 755 $< $@.$(version) && \ + $(INSTALL) -l $(@F).$(version) $@.$(version_M) && \ + exec $(INSTALL) -l $(@F).$(version_M) $@ + +$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes + exec $(INSTALL) -D -m 600 $< $@ + grep -- ^$(@F) < package/modes | { read name mode owner && \ + if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \ + chmod $$mode $@ ; } + +$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy + exec $(INSTALL) -D -m 644 $< $@ + +$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h + exec $(INSTALL) -D -m 644 $< $@ + +$(DESTDIR)$(includedir)/%.h: src/include/%.h + exec $(INSTALL) -D -m 644 $< $@ + +%.o: %.c + exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $< + +%.lo: %.c + exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $< + +$(ALL_BINS): + exec $(CC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS) + +lib%.a.xyzzy: + exec $(AR) rc $@ $^ + exec $(RANLIB) $@ + +lib%.so.xyzzy: + exec $(CC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS) + +.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-lib install-include + +.DELETE_ON_ERROR: @@ -0,0 +1,6 @@ +Changelog for apaste. + +In 0.0.1.0 +---------- + + - Initial release. @@ -0,0 +1,23 @@ +apaste - a command-line pastebin +-------------------------------- + + apaste is a simple implementation of a pastebin, to publish data +to a server via a short command line. + It was originally made for the Adélie Linux distribution, but +can be used anywhere. + See https://skarnet.org/software/apaste/ for details. + + +* Installation + ------------ + + See the INSTALL file. + + +* Contact information + ------------------- + + Laurent Bercot <ska-skaware at skarnet.org> + + Please use the <skaware at list.skarnet.org> 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 <<EOF +Usage: $0 [OPTION]... [TARGET] + +Defaults for the options are specified in brackets. + +System types: + --target=TARGET configure to run on target TARGET [detected] + --host=TARGET same as --target + +Installation directories: + --prefix=PREFIX main installation prefix [/] + --exec-prefix=EPREFIX installation prefix for executable files [PREFIX] + +Fine tuning of the installation directories: + --dynlibdir=DIR shared library files [PREFIX/lib] + --bindir=BINDIR user executables [EPREFIX/bin] + --libexecdir=DIR package-scoped executables [EPREFIX/libexec] + --libdir=DIR static library files [PREFIX/lib/$package] + --includedir=DIR C header files [PREFIX/include] + + If no --prefix option is given, by default libdir (but not dynlibdir) will be + /usr/lib/$package, and includedir will be /usr/include. + +Dependencies: + --with-sysdeps=DIR use sysdeps in DIR [PREFIX/lib/skalibs/sysdeps] + --with-include=DIR add DIR to the list of searched directories for headers + --with-lib=DIR add DIR to the list of searched directories for static libraries + --with-dynlib=DIR add DIR to the list of searched directories for shared libraries + + If no --prefix option is given, by default sysdeps will be fetched from + /usr/lib/skalibs/sysdeps. + +Optional features: + --enable-shared build shared libraries [disabled] + --disable-static do not build static libraries [enabled] + --disable-allstatic do not prefer linking against static libraries [enabled] + --enable-static-libc make entirely static binaries [disabled] + --disable-all-pic do not build executables or static libs as PIC [enabled] + --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled] + --enable-absolute-paths do not rely on PATH to access this package's binaries, + hardcode absolute BINDIR/foobar paths instead [disabled] + --enable-nsss use the nsss library for user information [disabled] + + --with-default-server=SERVER use SERVER as default server for apaste [adelielinux.xyz] + --with-default-port=PORT use PORT as default clear port for apaste [9999] + --with-default-tlsport=PORT use PORT as default TLS-enabled port for apaste [9997] + --with-default-cadir=CADIR use CADIR as trust anchor certificate location [/etc/ssl/certs] + --with-default-tls use secure connections by default [no] + --with-tmpdir=TMPDIR make temporary files in TMPDIR [/tmp] + +EOF +exit 0 +} + +# Helper functions + +# If your system does not have printf, you can comment this, but it is +# generally not a good idea to use echo. +# See http://etalabs.net/sh_tricks.html +echo () { + IFS=" " + printf %s\\n "$*" +} + +quote () { + tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/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 <<EOF +/* ISC license. */ + +/* Generated by: $cmdline */ + +#ifndef ${package_macro_name}_CONFIG_H +#define ${package_macro_name}_CONFIG_H + +#define ${package_macro_name}_VERSION "$version" +EOF +if $slashpackage ; then + echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\"" + echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\"" +elif $abspath ; then + echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\"" + echo "#define ${package_macro_name}_EXTBINPREFIX \"$bindir/\"" +else + echo "#define ${package_macro_name}_BINPREFIX \"\"" + echo "#define ${package_macro_name}_EXTBINPREFIX \"\"" +fi +echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\"" +echo +echo "#define ${package_macro_name}_DEFAULT_SERVER \"$server\"" +echo "#define ${package_macro_name}_DEFAULT_PORT $port" +echo "#define ${package_macro_name}_DEFAULT_TLSPORT $tlsport" +echo "#define ${package_macro_name}_DEFAULT_CADIR \"$cadir\"" +if $deftls ; then +echo "#define ${package_macro_name}_DEFAULT_TLS 1" +else +echo "#define ${package_macro_name}_DEFAULT_TLS 0" +fi +echo "#define ${package_macro_name}_TMPDIR \"$tmpdir\"" +echo +echo "#endif" +exec 1>&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 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>apaste: the apaste program</title> + <meta name="Description" content="apaste: the apaste program" /> + <meta name="Keywords" content="apaste client interface pastebin command-line tpaste sprunge fiche s6-networking tcpclient tlsclient tls ssl" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">apaste</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>apaste</tt> program </h1> + +<p> + <tt>apaste</tt> is a program that reads one or more files, or its +standard input, and sends the data to an <a href="apasted.html">apasted</a> +server. +</p> + +<h2> Interface </h2> + +<pre> + apaste [ -S | -s ] [ -C <em>cadir</em> ] [ -d <em>server</em>[<em>:port</em>] ] [ -r <em>rtimeout</em> ] [ -w <em>wtimeout</em> ] <em>file...</em> +</pre> + +<ul> + <li> apaste connects to a remote server via a plaintext or TLS-secured +connection, expecting to find an <a href="apasted.html">apasted</a> server at the +other end. </li> + <li> For every <em>file</em> given as argument, it sends the contents of <em>file</em> +over the network. If <em>file</em> is <tt>-</tt> (dash), then stdout is transmitted +until EOF. </li> + <li> The server answers with a blob of six printable characters, named a <em>slug</em>. +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. </li> + <li> apaste prints the slug to its stdout, then exits 0. </li> +</ul> + +<h2> Exit codes </h2> + +<dl> + <dt> 0 </dt> <dd> Success. The data has been recorded by the server and available in +some way as indicated by the slug. </dd> + <dt> 100 </dt> <dd> Bad usage. apaste was run in an incorrect way. </dd> + <dt> 111 </dt> <dd> System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. </dt> +</dl> + +<h2> Options </h2> + +<dl> + <dt> -S </dt> + <dd> Normal, plain text connection to the server, even if the built-in default +is TLS. The built-in default can be changed via the <tt>--with-default-tls</tt> +or <tt>--without-default-tls</tt> options to configure. </dd> + + <dt> -s </dt> + <dd> TLS connection to the server, even if the built-in default +is plain text. The built-in default can be changed via the <tt>--with-default-tls</tt> +or <tt>--without-default-tls</tt> options to configure. </dd> + + <dt> -C <em>cadir</em> </dt> + <dd> When using a TLS connection, use <em>cadir</em> 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 <tt>--with-default-cadir</tt> option to configure. </dd> + + <dt> -d <em>server</em>[<em>:port</em>] </dt> + <dd> Connect to server <em>server</em>, port <em>port</em>. The built-in defaults +can be changed via the <tt>--with-default-server</tt>, <tt>--with-default-port</tt>, +and <tt>--with-default-tlsport</tt> options to configure. </dd> + + <dt> -r <em>rtimeout</em> </dt> + <dd> If the server isn't answering with a slug within <em>rtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apaste will +wait forever for a server reply if necessary. </dd> + + <dt> -w <em>wtimeout</em> </dt> + <dd> If the server hasn't accepted all the data within <em>wtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apaste will +take as much time as it needs to send its data. </dd> +</dl> + +<h2> Example usage </h2> + +<ul> + <li> <code>$ echo Blah blah. | apaste -</code> </li> + <li> <code># apaste /etc/shadow </code> <small>(Just kidding. Don't do that.)</small> </li> +</ul> + +<h2> Notes </h2> + +<ul> + <li> apaste is only a wrapper around +<a href="//skarnet.org/software/s6-networking/s6-tcpclient.html">s6-tcpclient</a> +(for plain connections) or +<a href="//skarnet.org/software/s6-networking/s6-tlsclient.html">s6-tlsclient</a> +(for TLS-tunneled connections), and +<a href="apastec.html">apastec</a> 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. </li> + <li> <tt>-</tt>, i.e. stdin, cannot be mentioned several times as an argument. It +can be transmitted with other files, but cannot be duplicated. </li> +</ul> + +</body> +</html> 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 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>apaste: the apastec program</title> + <meta name="Description" content="apaste: the apastec program" /> + <meta name="Keywords" content="apastec apaste client interface pastebin command-line tpaste sprunge fiche" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">apaste</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>apastec</tt> program </h1> + +<p> + <tt>apastec</tt> is a program that reads one or more files, or its +standard input, and sends them to a preopened file descriptor. +</p> + +<h2> Interface </h2> + +<pre> + apastec [ -r <em>rtimeout</em> ] [ -w <em>wtimeout</em> ] <em>file...</em> +</pre> + +<ul> + <li> 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 +<a href="apasted.html">apasted</a> server. </li> + <li> For every <em>file</em> given as argument, it sends the contents of <em>file</em> +over the network. If <em>file</em> is <tt>-</tt> (dash), then stdout is transmitted +until EOF. </li> + <li> The server answers with a blob of six printable characters, named a <em>slug</em>. +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. </li> + <li> apastec prints the slug to its stdout, then exits 0. </li> +</ul> + +<h2> Exit codes </h2> + +<dl> + <dt> 0 </dt> <dd> Success. The data has been recorded by the server and available in +some way as indicated by the slug. </dd> + <dt> 100 </dt> <dd> Bad usage. apaste was run in an incorrect way. </dd> + <dt> 111 </dt> <dd> System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. </dt> +</dl> + +<h2> Options </h2> + +<dl> + <dt> -r <em>rtimeout</em> </dt> + <dd> If the server isn't answering with a slug within <em>rtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apastec will +wait forever for a server reply if necessary. </dd> + + <dt> -w <em>wtimeout</em> </dt> + <dd> If the server hasn't accepted all the data within <em>wtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apastec will +take as much time as it needs to send its data. </dd> +</dl> + +<h2> Typical usage </h2> + +<p> + apastec isn't meant to be used directly. It is meant to be invoked as +part of a command line crafted by the <a href="apaste.html">apaste</a> +command, where programs from the +<a href="//skarnet.org/software/s6-networking/">s6-networking</a> package +establish the connection to the server, then exec into apastec to read +the user's data and transmit them with the apaste protocol. +</p> + +<h2> Notes </h2> + +<ul> + <li> <tt>-</tt>, i.e. stdin, cannot be mentioned several times as an argument. It +can be transmitted with other files, but cannot be duplicated. </li> +</ul> + +</body> +</html> 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 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>apaste: the apasted program</title> + <meta name="Description" content="apaste: the apasted program" /> + <meta name="Keywords" content="apasted apaste server pastebin command-line tpaste sprunge fiche" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">apaste</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>apasted</tt> program </h1> + +<p> + <tt>apasted</tt> 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 <a href="apastec.html">apastec</a> client. It reads a +series of files transmitted by the client, stores it on the server, and +sends back a <em>slug</em> to the client, i.e. an identifier for the +stored files. +</p> + +<h2> Interface </h2> + +<pre> + apasted [ -r <em>rtimeout</em> ] [ -w <em>wtimeout</em> ] [ -d <em>rootdir</em> ] [ -p <em>prefix</em> ] [ -m <em>maxfiles</em> ] +</pre> + +<ul> + <li> apasted reads data on its stdin, expecting the protocol spoken by the +<a href="apastec.html">apastec</a> client, containing one or more files. </li> + <li> It creates a subdirectory <em>subdir</em> in its working directory, +and stores the files it receives under it. + <ul> + <li> If it only receives one file, it stores it in <tt><em>subdir</em>/index.txt</tt>. </li> + <li> If it receives two or more files, it stores each file <em>file</em> as +<tt><em>subdir</em>/<em>file</em>.txt</tt>, and creates a +<tt><em>subdir</em>/index.html</tt> file with hyperlinks to every file in <em>subdir</em>. </li> + </ul> </li> + <li> It sends the <em>subdir</em> name back to the client, as a <em>slug</em>. </li> + <li> It exits 0 </li> +</ul> + +<h2> Exit codes </h2> + +<dl> + <dt> 0 </dt> <dd> Success. </dd> + <dt> 1 </dt> <dd> Protocol error. The client sent incorrectly formatted data. </dd> + <dt> 100 </dt> <dd> Bad usage. apasted was run in an incorrect way. </dd> + <dt> 111 </dt> <dd> System call failed. This usually signals an issue with the +underlying operating system, or with the network in some way. </dt> +</dl> + +<h2> Options </h2> + +<dl> + <dt> -r <em>rtimeout</em> </dt> + <dd> If the client hasn't transmitted all its data within <em>rtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apasted will +wait forever for client data if necessary. </dd> + + <dt> -w <em>wtimeout</em> </dt> + <dd> If apasted fails to send the slug to the client within <em>wtimeout</em> +milliseconds, give up. The default is 0, meaning infinite: apasted will +take as much time as it needs to send its answer. </dd> + + <dt> -d <em>rootdir</em> </dt> + <dd> Switch to <em>rootdir</em> and store files there. The default is +apasted's working directory. </dd> + + <dt> -p <em>prefix</em> </dt> + <dd> When sending a slug to the client, prefix <em>subdir</em> with <em>prefix</em>, +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 <em>prefix</em> +is the URL of apasted's base directory, then the slug can directly be used as a +URL to access the client's files. </dd> + + <dt> -m <em>maxfiles</em> </dt> + <dd> Accept a maximum of <em>maxfiles</em> 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. </dd> +</dl> + +<h2> Typical usage </h2> + +<ul> + <li> apasted is meant to be run under a super-server accepting client connections. +Run it under inetd or +<a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a> +for plaintext connections, and under +<a href="//skarnet.org/software/s6-networking/s6-tlsserver.html">s6-tlsserver</a> +for TLS-tunneled connections. </li> + <li> 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 +<tt>-p</tt> option on the apasted command line to make sure the client receives +a full URL to its files. </li> +</ul> + +<h2> Caveats </h2> + +<ul> + <li> apaste is a <em>push</em> 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: + <ul> + <li> If possible, have quotas on the filesystem hosting the apasted storage area </li> + <li> Use the <tt>-m</tt> option to avoid trivial inode exhaustion attacks </li> + <li> Use your super-server's options to mitigate client patterns of abuse, log and +block the IPs of problematic clients </li> + <li> Run scripts that regularly delete old <em>subdir</em>s (and their contents) +in the apasted storage area. </li> + <li> 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. </li> + </ul> </li> +</ul> + +<h2> Notes </h2> + +<ul> + <li> apasted will store a file named <em>file</em> as <em>file.txt</em> 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. </li> + <li> A unique file is stored as <tt><em>slug</em>/index.txt</tt>; if apasted is +run with <tt>-p http://example.com/</tt> then the apaste client, on success, +will print <tt>http://example.com/<em>slug</em>/</tt>. Make sure that your web server can +automatically interpret that URL as <tt>http://example.com/<em>slug</em>/index.txt</tt>. </li> +</ul> + +</body> +</html> 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 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>apaste - a small command-line pastebin</title> + <meta name="Description" content="apaste - a small command-line pastebin" /> + <meta name="Keywords" content="apaste pastebin tpaste fiche command line laurent bercot ska skarnet" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> apaste </h1> + +<h2> What is it ? </h2> + +<p> + 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. +</p> + +<hr /> + +<h2> Installation </h2> + +<h3> Requirements </h3> + +<ul> + <li> A POSIX-compliant system with a standard C development environment </li> + <li> GNU make, version 3.81 or later </li> + <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> 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. </li> + <li> <a href="//skarnet.org/software/s6-networking/">s6-networking</a> 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. </li> +</ul> + +<h3> Licensing </h3> + +<p> + apaste is free software. It is available under the +<a href="https://opensource.org/licenses/ISC">ISC license</a>. +</p> + +<h3> Download </h3> + +<ul> + <li> The current released version of apaste is +<a href="apaste-0.0.1.0.tar.gz">0.0.1.0</a>. </li> + <li> You can checkout a copy of the +<a href="//git.skarnet.org/cgi-bin/cgit.cgi/apaste/">apaste +git repository</a>: +<pre> git clone git://git.skarnet.org/apaste </pre> </li> + <li> There's also a +<a href="https://github.com/skarnet/apaste">GitHub mirror</a> +of the apaste git repository. </li> +</ul> + +<h3> Compilation </h3> + +<ul> + <li> See the enclosed INSTALL file for installation details. </li> +</ul> + +<h3> Upgrade notes </h3> + +<ul> + <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between +the previous versions of apaste and the current one. </li> +</ul> + +<hr /> + +<h2> Reference </h2> + +<h3> Commands </h3> + +<ul> + <li> <a href="apaste.html">The <tt>apaste</tt> program</a> </li> + <li> <a href="apastec.html">The <tt>apastec</tt> program</a> </li> + <li> <a href="apasted.html">The <tt>apasted</tt> program</a> </li> +</ul> + +<h2> Related resources </h2> + +<ul> + <li> <tt>apaste</tt> is discussed on the +<a href="//skarnet.org/lists/#skaware">skaware</a> mailing-list. </li> +</ul> + +<h2> Similar work </h2> + +<ul> + <li> <a href="https://github.com/solusipse/fiche">fiche</a> is also +a small command-line pastebin utility. </li> + <li> <a href="https://tpaste.us/">tpaste</a> and +<a href="https://sprunge.us/">sprunge </a> are similar utilities, +one written in lua, the other in Python. </li> +</ul> + +</body> +</html> 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 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>apaste: how to upgrade</title> + <meta name="Description" content="apaste: how to upgrade" /> + <meta name="Keywords" content="apaste installation upgrade" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">apaste</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> What has changed in apaste </h1> + +<h2> in 0.0.1.0 </h2> + +<ul> + <li> Initial release. </li> +</ul> + +</body> +</html> 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 <stdint.h> +#include <string.h> + +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/exec.h> + +#include <s6-networking/config.h> + +#include <apaste/config.h> + +#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 <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <signal.h> + +#include <skalibs/posixplz.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint64.h> +#include <skalibs/buffer.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/sig.h> +#include <skalibs/djbunix.h> +#include <skalibs/unix-timed.h> + +#include <apaste/config.h> +#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 <sys/types.h> + +#include <skalibs/buffer.h> +#include <skalibs/tai.h> + + +/* 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 <skalibs/sysdeps.h> + +#ifdef SKALIBS_HASSENDFILE + +#include <sys/types.h> +#include <sys/sendfile.h> +#include <limits.h> + +#include <skalibs/uint64.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +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 <sys/uio.h> +#include <unistd.h> +#include <stdint.h> + +#include <skalibs/uint64.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +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 <stdint.h> +#include <string.h> +#include <sys/uio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <signal.h> + +#include <skalibs/posixplz.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint64.h> +#include <skalibs/bytestr.h> +#include <skalibs/siovec.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/buffer.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/sig.h> +#include <skalibs/djbunix.h> +#include <skalibs/unix-timed.h> + +#include <apaste/config.h> +#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 "\ +<html>\n\ + <head>\n\ + <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\ + <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n\ + <meta http-equiv=\"Content-Language\" content=\"en\" />\n\ + <title>apaste results</title>\n\ + <meta name=\"Description\" content=\"apaste results\" />\n\ + </head>\n\ +<body>\n\ +<h3> apaste results </h3>\n\ +<ul>\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, " <li> <a href=\"") == -1 + || buffer_puts(ib, name) == -1 + || buffer_puts(ib, ".txt\">") == -1 + || buffer_puts(ib, name) == -1 + || buffer_puts(ib, "</a> (") == -1 + || buffer_put(ib, fmt, m) == -1 + || buffer_puts(ib, " bytes) </li>\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, "</ul>\n</body>\n</html>\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 |
