pax_global_header00006660000000000000000000000064145221646650014525gustar00rootroot0000000000000052 comment=5a26476c4303a93bfb9fa375ab6b78f36dd4233c execline-2.9.4.0/000077500000000000000000000000001452216466500134735ustar00rootroot00000000000000execline-2.9.4.0/.gitignore000066400000000000000000000011401452216466500154570ustar00rootroot00000000000000*.o *.lo /*.a.xyzzy /*.so.xyzzy /config.mak /src/include/execline/config.h /src/multicall/execline.c /execline /background /backtick /case /define /dollarat /elgetopt /elgetpositionals /elglob /eltest /emptyenv /envfile /exec /execlineb /execline-cd /execline-umask /exit /export /fdblock /fdclose /fdmove /fdswap /fdreserve /forbacktickx /foreground /forstdin /forx /getcwd /getpid /heredoc /homeof /if /ifelse /ifte /ifthenelse /import /importas /loopwhilex /multidefine /multisubstitute /pipeline /piperw /posix-cd /posix-umask /redirfd /runblock /shift /trap /tryexec /umask /unexport /wait /withstdinas execline-2.9.4.0/AUTHORS000066400000000000000000000021211452216466500145370ustar00rootroot00000000000000Main author: Laurent Bercot Contributors: Jean Marot Paul Jarc Eric Le Bihan Rasmus Villemoes Colin Booth Mira Ressel Alexis Dominique Martinet Christian Hohnstaedt Eugen Wissner Thanks to: Dan J. Bernstein David Madore Nicolas George Joël Riou Matthew R. Dempsky Lasse Kliemann Vallo Kallaste Jorge Almeida Olivier Brunel Jesse Young Danilo Spinella Éric Vidal Profpatsch Guillermo Michael Zuo Casper Ti. Vector execline-2.9.4.0/CONTRIBUTING000066400000000000000000000004371452216466500153310ustar00rootroot00000000000000 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/ execline-2.9.4.0/COPYING000066400000000000000000000013701452216466500145270ustar00rootroot00000000000000Copyright (c) 2011-2023 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. execline-2.9.4.0/DCO000066400000000000000000000026151452216466500140270ustar00rootroot00000000000000Developer 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. execline-2.9.4.0/INSTALL000066400000000000000000000167111452216466500145320ustar00rootroot00000000000000Build Instructions ------------------ * Requirements ------------ - A POSIX-compliant C development environment - GNU make version 3.81 or later - skalibs version 2.14.0.0 or later: https://skarnet.org/software/skalibs/ - Optional: nsss version 0.2.0.4 or later: https://skarnet.org/software/nsss/ This software will run on any operating system that implements POSIX.1-2008, available at: https://pubs.opengroup.org/onlinepubs/9699919799/ * Standard usage -------------- ./configure && make && sudo make install will work for most users. It will install the binaries in /bin and the static libraries in /usr/lib/execline. Please note that static libraries in /usr/lib/execline *will not* be found by a default linker invocation: you need -L/usr/lib/execline. Other skarnet.org software automatically handles that case if the default configuration is used, but if you change the configuration, remember to use the appropriate --with-lib configure option. 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. (If you are using a GNU/Linux system, 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/) execline is especially efficient when statically linked, so it is recommended if you have a suitable libc. * 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. * Multicall binary ---------------- Starting with version 2.9.2.0, the execline package comes with an alternative build in the form of a multicall binary, simply called "execline", that includes the functionality of *all* the other binaries; it switches functionalities depending on the name it is called with, or the subcommand it is given: "execline cd / true" will chdir to / before exiting, same as "cd / true" if cd is a link to the execline program. To use this, use the --enable-multicall option to configure. Only the execline binary will be built, and other programs will be created as symbolic links to execline at installation time. The multicall setup saves a lot of disk space, at the price of an unnoticeable amount of CPU usage. RAM usage is about equivalent and difficult to assess. The setup is meant for embedded devices or small distributions with a focus on saving disk space. execline-2.9.4.0/Makefile000066400000000000000000000123341452216466500151360ustar00rootroot00000000000000# # 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 := BIN_SYMLINKS := 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 define binary_installation_rule $(DESTDIR)$(1)/$(2): $(2) 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 $$@ ; } endef define symlink_installation_rule $(DESTDIR)$(1)/$(2): $(DESTDIR)$(1)/$(SYMLINK_TARGET_$(2)) exec $(INSTALL) -l $$( Please use the mailing-list for questions about execline. execline-2.9.4.0/README.macos000066400000000000000000000002531452216466500154540ustar00rootroot00000000000000 This package will compile and run on Darwin (MacOS), but the building of shared libraries is not supported. Make sure you use the --disable-shared option to configure. execline-2.9.4.0/README.solaris000066400000000000000000000006531452216466500160320ustar00rootroot00000000000000 This package assumes the existence of a POSIX shell in /bin/sh. On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide a POSIX shell in /usr/xpg4/bin/sh. To compile this package on Solaris, you will need to run ./patch-for-solaris before you run ./configure. This script will change the #! invocation of the configure script and various tools so that a POSIX shell is used for the compilation process. execline-2.9.4.0/configure000077500000000000000000000355301452216466500154100ustar00rootroot00000000000000#!/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' shebangdir='$bindir' shebangisdefault=true sysdeps='$prefix/lib/skalibs/sysdeps' manualsysdeps=false shared=false static=true allpic=true slashpackage=false abspath=false usensss=false pposix=false multicall=false sproot= home= exthome= allstatic=true evenmorestatic=false addincpath='' addlibspath='' addlibdpath='' vpaths='' vpathd='' build= for arg ; do case "$arg" in --help) usage ;; --prefix=*) prefix=${arg#*=} ;; --exec-prefix=*) exec_prefix=${arg#*=} ;; --dynlibdir=*) dynlibdir=${arg#*=} ;; --libexecdir=*) libexecdir=${arg#*=} ;; --bindir=*) bindir=${arg#*=} ;; --libdir=*) libdir=${arg#*=} ;; --includedir=*) includedir=${arg#*=} ;; --shebangdir=*) shebangisdefault=false ; shebangdir=${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-pedantic-posix|--enable-pedantic-posix=yes) pposix=true ;; --disable-pedantic-posix|--enable-pedantic-posix=no) pposix=false ;; --enable-multicall|--enable-multicall=yes) multicall=true ;; --disable-multicall|--enable-multicall=no) multicall=false ;; --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; --host=*|--target=*) target=${arg#*=} ;; --build=*) build=${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 shebangdir 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 if $shebangisdefault ; then shebangdir=${extbinprefix} fi 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 if $allpic ; then tryflag CPPFLAGS_AUTO -fPIC 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) 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 if $pposix ; then echo "PEDANTIC_POSIX := 1" else echo "PEDANTIC_POSIX :=" fi if $multicall ; then echo "MULTICALL := 1" else echo "MULTICALL :=" 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." execline-2.9.4.0/doc/000077500000000000000000000000001452216466500142405ustar00rootroot00000000000000execline-2.9.4.0/doc/background.html000066400000000000000000000032101452216466500172410ustar00rootroot00000000000000 execline: the background command

execline
Software
skarnet.org

The background program

background launches a command in the background, then goes on with the execution flow.

Interface

In an execlineb script:

     background [ -d ] { prog1... } prog2...
  • background reads a prog1... command in a block and unquotes it.
  • It spawns a child executing prog1....
  • It sets the ! environment variable to the pid of the prog1... process.
  • It then execs into prog2....

Options

  • -d : doublefork. If the -d option is set, prog1... will run as a grandchild of background.

Notes

  • background prog1... "" prog2... is equivalent to sh -c 'prog1... & ; exec prog2...'.
execline-2.9.4.0/doc/backtick.html000066400000000000000000000057171452216466500167130ustar00rootroot00000000000000 execline: the backtick command

execline
Software
skarnet.org

The backtick program

backtick runs a program and stores its output in an environment variable, then executes another program.

Interface

In an execlineb script:

     backtick [ -i | -I | -x | -D default ] [ -N | -n ] [ -E | -e ] variable { prog1... } prog2...
  • backtick reads prog1... in a block and unquotes it.
  • It runs prog1... as a child process and saves its output in memory. This output must not contain a null character.
  • backtick execs into prog2..., with variable added to the environment with prog1...'s output as a value.

Options

  • -N : store prog1...'s output as is, including the last newline, if any.
  • -n : chomp an ending newline off prog1...'s output. This is the default.
  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of exec'ing into prog2..., exec into importas -ui variable variable prog2.... This substitutes variable into the command line instead of putting it into the environment.

The other options tell backtick what to do if prog1...'s output is not suitable as the contents of an environment variable (i.e. it contains a null character) or if prog1... crashes or exits nonzero:

  • -i : backtick exits with an approximation of prog1's exit code, or 124 if prog1 wrote a null character. This is the default.
  • -I: the value of variable is set to whatever the start of prog1...'s output is, up to the first null character, or to whatever prog1... wrote before crashing; chomping is applied if required; then execution proceeds.
  • -x : variable is removed from the environment, and execution proceeds.
  • -D default : the value of variable is set to default, and execution proceeds.
execline-2.9.4.0/doc/case.html000066400000000000000000000146701452216466500160510ustar00rootroot00000000000000 execline: the case command

execline
Software
skarnet.org

The case program

case compares a value against a series of regular expressions, and executes into a program depending on the first expression the value matches.

Interface

In an execlineb script:

     case [ -S | -s ] [ -E | -e ] [ -i ] [ -n | -N ] value
     {
       [ regex { prog... } ]
       [ regex { prog... } ]
       ...
     }
     progdefault...
  • case reads an argument value and a sequence of directives in a block.
  • Each directive is a regular expression followed by a block.
  • case matches value against the regular expressions in the order they are given.
  • As soon as value matches a regex, case executes into the prog... command line that immediately follows the matched regex.
  • If value matches no regex, case eventually execs into progdefault..., or exits 0 if progdefault... is empty.

Options

  • -s : Shell matching. The regex words will not be interpreted as regular expressions, but as shell expressions to be interpreted via fnmatch(). The other options also change meanings, see the Shell matching section below.
  • -S : Regular expression matching. This is the default. This section, and all of the sections below except the Shell matching one, assumes that it is the case.
  • -e : Interpret the regex words as basic regular expressions.
  • -E : Interpret the regex words as extended regular expressions. This is the default.
  • -i : Perform case-insensitive matches.
  • -N : Make the matching expression and subexpressions available to prog's environment. See the "Subexpression matching" section below.
  • -n : Do not transmit the matching expression and subexpressions to prog... via the environment. This is the default.

Subexpression matching

If the -N option has been given, and value matches a regex, then case will run prog with a modified environment:

  • The 0 variable will contain the regex that value matched.
  • The # variable will contain the number of subexpressions in regex.
  • For every integer i between 1 and the number of subexpressions (included), the variable i contains the part of value that matched the ith subexpression in regex.

To retrieve that information into your command line in an execline script, you can use the elgetpositionals program.

An example

Consider the following script; say it's named match.

#!/bin/execlineb -S1
emptyenv
case -N -- $1
{
  "([fo]+)bar(baz)" { /usr/bin/env }
}

Running match foooobarbaz will print the following lines, corresponding to the output of the /usr/bin/env command:

#=2
0=([fo]+)bar(baz)
1=foooo
2=baz

Shell matching

If the -s option has been given to case, then the regex words are not interpreted as regular expressions, but as shell patterns, as is performed by the shell's case conditional construct. This has the following consequences:

  • Subexpression matching is always disabled.
  • prog... is always executed with an unmodified environment.
  • The options to the case command change meanings: instead of controlling how the regex regular expressions are interpreted by the regcomp() primitive, they now control how value is matched against the regex patterns (which are not regular expressions!) via the fnmatch() primitive. Namely:
    • -e : Treat a backslash as an ordinary character; do not allow character escaping in patterns. (This sets the FNM_NOESCAPE flag.)
    • -E : Allow backslash escaping in patterns. This is the default. (This clears the FNM_NOESCAPE flag.)
    • -i : Treat a period (.) as a special character for matching (set FNM_PERIOD). By default, the period is not a special character (FNM_PERIOD is cleared).
    • -N : Treat patterns as pathnames: make slashes character special. (This sets the FNM_PATHNAME flag.)
    • -n : Do not treat patterns as pathnames (clear the FNM_PATHNAME flag). This is the default.

Notes

  • value must match regex as a full word. If only a substring of value matches regex, it is not considered a match.
  • If value matches no regex, progdefault... is always executed with an unmodified environment, whether subexpression matching has been requested or not.
execline-2.9.4.0/doc/componentsb.txt000066400000000000000000000031441452216466500173320ustar00rootroot00000000000000#!/command/execlineb -P # This execlineb script will sleep for 1 second, then print some # silly things on the standard output. foreground # an unquoted string, evaluated to: foreground { # A single opening brace, not included in the argv sleep 1 # Two unquoted strings, evaluated to " sleep" and " 1" # (without the quotation marks). } # A single closing brace, evaluated to the empty word "echo" # this is a quoted string. It will evaluate to the word: echo foo\ bar\ zoinx # This is one word, since the spaces are escaped "foo bar zoinx" # This is exactly the same word, written another way " # this is not a comment, since it is inside a quoted string # This is not a comment either \" # nor is this " # but this is one "\0x41\66\0103D\n" # This is the string ABCD followed by a newline. # Be careful: the newline will be part of the word. \n # this is not a newline, but the single word: n $23 # This will NOT be replaced by anything with execline-1.y, unless # substitution is explicitly asked for in the script. # The dollar is no special character for the execline binary. baz"$1"qux # This will evaluate to the word baz$1qux baz\$1qux # Same here baz$1qux # Same here in execline-1.y ${PATH} # This will NOT be replaced by execline ; use the importas command # if you need the $PATH value. 'this is not a string' # it will be parsed as five separate words "\ " # This will be parsed as the empty word. A (backslash, newline) # sequence inside a quoted string is entirely removed. execline-2.9.4.0/doc/define.html000066400000000000000000000024221452216466500163600ustar00rootroot00000000000000 execline: the define command

execline
Software
skarnet.org

The define program

define replaces a literal with a value, then executes another program.

Interface

     define [ -s ] [ -C | -c ] [ -N | -n ] [ -d delim ] variable value prog...
execline-2.9.4.0/doc/dieshdiedie.html000066400000000000000000000312151452216466500173700ustar00rootroot00000000000000 execline: why execline and not sh

execline
Software
skarnet.org

Why not just use /bin/sh?

Security

One of the most frequent sources of security problems in programs is parsing. Parsing is a complex operation, and it is easy to make mistakes while designing and implementing a parser. (See what Dan Bernstein says on the subject, section 5.)

But shells parse all the time. Worse, the essence of the shell is parsing: the parser and the runner are intimately interleaved and cannot be clearly separated, thanks to the specification. The shell performs several kinds of expansions, automatic filename globbing, and automatic word splitting, in an unintuitive order, requiring users to memorize numerous arbitrary quoting rules in order to achieve what they want. Pages abound where common mistakes are listed, more often than not leading to security holes. Did you know that "$@" is a special case of double quoting, because it will split the arguments into several words, whereas every other use of double quotes in a shell is meant to prevent splitting?

execlineb parses the script only once: when reading it. The parser has been designed to be simple and systematic, to reduce the potential for bugs - which you just cannot do with a shell. After execlineb has split up the script into words, no other parsing phase will happen, unless the user explicitly requires it. Positional parameters, when used, are never split, even if they contain spaces or newlines, unless the user explicitly requires it. Users control exactly what is split, what is done, and how.

Portability

The shell language was designed to make scripts portable across various versions of Unix. But it is actually really hard to write a portable shell script. There are dozens of distinct sh flavours, not even counting the openly incompatible csh approach and its various tcsh-like followers. The ash, bash, ksh and zsh shells all exhibit a different behaviour, even when they are run with the so-called compatibility mode. From what I have seen on various experiments, only zsh is able to follow the specification to the letter, at the expense of being big and complex to configure. This is a source of endless problems for shell script writers, who should be able to assume that a script will run everywhere, but cannot in practice. Even a simple utility like test cannot be used safely with the normalized options, because most shells come with a builtin test that does not respect the specification to the letter. And let's not get started about echo, which has its own set of problems. Rich Felker has a page listing tricks to use to write portable shell scripts. Writing a portable script should not be that hard.

execline scripts are portable. There is no complex syntax with opportunity to have an undefined or nonportable behaviour. The execline package is portable across platforms: there is no reason for vendors or distributors to fork their own incompatible version. Scripts will not break from one machine to another; if they do, it's not a "portability problem", it's a bug. You are then encouraged to find the program that is responsible for the different behaviour, and send a bug-report to the program author - including me, if the relevant program is part of the execline distribution.

A long-standing problem with Unix scripts is the shebang line, which requires an absolute path to the interpreter. Scripts are only portable as is if the interpreter can be found at the same absolute path on every system. With /bin/sh, it is almost the case (Solaris manages to get it wrong by having a non-POSIX shell as /bin/sh and requiring something like #!/usr/xpg4/bin/sh to get a POSIX shell to interpret your script). Other scripting languages are not so lucky: perl can be /bin/perl, /usr/bin/perl, /usr/local/bin/perl or something else entirely. For those cases, some people advocate the use of env: #!/usr/bin/env perl. But first, env can only find interpreters that can be found via the user's PATH environment variable, which defeats the purpose of having an absolute path in the shebang line in the first place; and second, this only displaces the problem: the env utility does not have a guaranteed absolute path. /usr/bin/env is the usual convention, but not a strong guarantee: it is valid for systems to have /bin/env instead, for instance.

execline suffers from the same issues. #!/bin/execlineb ? #!/usr/bin/execlineb ? This is the only portability problem that you will find with execline, and it is common to every script language.

The real solution to this portability problem is a convention that guarantees fixed absolute paths for executables, which the FHS does not do. The slashpackage convention is such an initiative, and is well-designed; but as with every convention, it only works if everyone follows it, and unfortunately, slashpackage has not found many followers. Nevertheless, like every skarnet.org package, execline can be configured to follow the slashpackage convention.

Simplicity

I originally wanted a shell that could be used on an embedded system. Even the ash shell seemed big, so I thought of writing my own. Hence I had a look at the sh specification... and ran away screaming. This specification is insane. It goes against every good programming practice; it seems to have been designed only to give headaches to wannabe sh implementors.

POSIX cannot really be blamed for that: it only normalizes existing, historical behaviour. One can argue whether it is a good idea to normalize atrocious behaviour for historical reasons, as is the case with the infamous gets function, but this is the way it is.

The fact remains that modern shells have to be compatible with that historical nonsense and that makes them big and complex at best, or incompatible and ridden with bugs at worst. An OpenBSD developer said to me, when asked about the OpenBSD /bin/sh: "It works, but it's far from not being a nightmare".

Nobody should have nightmare-like software on their system. Unix is simple. Unix was designed to be simple. And if, as Dennis Ritchie said, "it takes a genius to understand the simplicity", that's because incompetent people took advantage of the huge Unix flexibility to write insanely crappy or complex software. System administrators can only do a decent job when they understand how the programs they run are supposed to work. People are slowly starting to grasp this (or are they? We finally managed to get rid of sendmail and BIND, but GNU/Linux users seem happy to welcome the era of D-Bus and systemd. Will we ever learn?) - but even sh, a seemingly simple and basic Unix program, is hard to understand when you lift the cover.

So I decided to forego sh entirely and take a new approach. So far it has been working. The execline specification is simple, and, as I hope to have shown, easy to implement without too many bugs or glitches.

Performance

Since it was made to run on an embedded system, execline was designed to be light in memory usage. And it is.

  • No overhead due to interactive support.
  • No overhead due to unneeded features. Since every command performs its task then executes another command, all occupied resources are instantly freed. By contrast, a shell stays in memory during the whole execution time.
  • Very limited use of the C library. Only the C interface to the kernel's system calls, and some very basic functions like malloc(), are used in the C library. In addition to avoiding the horrible interfaces like stdio and the legacy libc bugs, this approach makes it easy to statically compile execline - you will want to do that on an embedded system, or just to gain performance.

You can have hundreds of execline scripts running simultaneously on an embedded box. Not exactly possible with a shell.

For scripts that do not require many computations that a shell can do without calling external programs, execline is faster than the shell. Unlike sh's one, the execline parser is simple and straightforward; actually, it's more of a lexer than a parser, because the execline language has been designed to be LL(1) - keep it simple, stupid. execline scripts get analysed and launched practically without a delay.

  • The best use case of execline is a linear, straightforward script, a simple command line that does not require the shell's processing power. In that case, execline will skip the shell's overhead and win big time on resource usage and execution speed.
  • For longer scripts that fork a few commands, with a bit of control flow, on average, an execline script will run at roughly the same speed as the equivalent shell script, while using less resources.
  • The worst use case of execline is when the shell is used as a programming language, and the script loops over complex internal constructs that execline is unable to replicate without forking. In that case, execline will waste a lot of time in fork/exec system calls that the shell does not have to perform, and be noticeably slower. execline has been designed as a scripting language, not as a programming language: it is efficient at being the glue that ties together programs doing a job, not at implementing a program's logic.

execline limitations

  • execline can only handle scripts that fit in one argv. Unix systems have a limit on the argv+envp size; execline cannot execute scripts that are bigger than this limit.
  • execline commands do not perform signal handling. It is not possible to trap signals efficiently inside an execline script. The trap binary, part of the execline suite, provides a signal management primitive, but it is more limited and slower than its equivalent shell construct.
  • Due to the execline design, maintaining a state is difficult. Information has to transit via environment variables or temporary files, which makes commands like loopwhilex a bit painful to handle.
  • Despite all its problems, the main shell advantage (apart from being available on every Unix platform, that is) is that it is often convenient. Shell constructs can be terse and short, where execline constructs will be verbose and lengthy.
  • An execline script is generally heavier on execve() than the average shell script - notably in programs where the shell can use builtins. This can lead to a performance loss, especially when executed programs make numerous calls to the dynamic linker: the system ends up spending a lot of time resolving dynamic symbols. If it is a concern to you, you should try and statically compile the execline package, to eliminate the dynamic resolution costs. Unless you're heavily looping around execve(), the remaining costs will be negligible.
execline-2.9.4.0/doc/dollarat.html000066400000000000000000000057301452216466500167350ustar00rootroot00000000000000 execline: the dollarat command

execline
Software
skarnet.org

The dollarat program

dollarat prints the positional parameters of an execline script.

Interface

     dollarat [ -n ] [ -0 | -d delimchar ]
  • dollarat reads the number n of "positional parameters" in the # environment variable. If that variable is not set or does not contain a valid n, dollarat exits 100.
  • dollarat prints the value of the 1 environment variable, then delimchar, then the value of the 2 environment variable... and so on until n. If one of these variables is not set, dollarat exits 100.
  • If everything runs OK, dollarat exits 0. This makes it one of the rare "exiting" execline commands.

Options

  • -n : chomp. Do not print the last delimchar.
  • -d delimchar : use the character delimchar as separator between the arguments. Default: \n. If delimchar has more than one character, only the first one is used. If delimchar is the empty string, then dollarat will output the positional parameters as a sequence of netstrings (and the -n option will be ignored).
  • -0 : use the null character as separator. If this option and the -d option are given concurrently, the rightmost one wins. Warning: -0 should only be used to feed data to programs that know how to handle null-separated lists.

Notes

  • You can use dollarat -d "" along with the forbacktickx command to reliably loop over the positional parameters:
     #!/command/execlineb
     forbacktickx -d "" ARG { dollarat -d "" }
     dosomething $ARG
    
    will call dosomething in turn on each argument to the script. That will work even if those arguments contain spaces, newlines, or other fancy characters.
  • Alternatively, instead of encoding data into a netstring, you can use a null-separated list, which will work the same way:
     #!/command/execlineb
     forbacktickx -0 ARG { dollarat -0 }
     dosomething $ARG
    
execline-2.9.4.0/doc/el_pushenv.html000066400000000000000000000121171452216466500173000ustar00rootroot00000000000000 execline: pushing and popping the environment

execline
Software
skarnet.org

Pushing and popping the environment

The execlineb launcher can store positional parameters, i.e. arguments given to your script, into the environment. The # variable contains the number of arguments; the 0 variable contains the name of your execline script; the 1 variable contains the first argument; and so on.

Up to execline-1.04, this could create problems with nested scripts: the inner script would overwrite the outer script's parameters, and there was no way to get them back. In particular, writing execline commands in the execline language via the runblock command was impossible.

To solve that issue
, execline now implements a kind of environment stack. When execlineb reads the arguments, it does not overwrite the positional parameters, but pushes them on a stack:

  • # will be set to the current number of arguments
  • but if a variable named # existed before, it is renamed #:1
  • and if a variable named #:1 also existed, it is renamed #:2
  • ... and so on until #:n+1 doesn't exist.

Same goes for the other positional parameters.

The script then runs; and commands such as elgetpositionals use the current frame of positional parameters, without paying attention to the deeper levels.

When you are done with the arguments
, it is advisable to drop the current frame, and pop the environment stack to get it back to its previous state:

  • # will be unset
  • but if #:1 exists, it will be renamed #
  • and if #:2 exists, it will be renamed #:1
  • ... and so on until #:n+1 doesn't exist.

Again, same goes for the other positional parameters.
The runblock command will perform that pop operation automatically; the standard "manual" way to perform it is to use the emptyenv -P command.

A pop example

Suppose you want to run the long-lived program prog after printing the list of its arguments.

 #!/command/execlineb
 elgetpositionals
 foreground { echo $0 $@ }
 prog $@

will work, but will pollute prog's environment with a set of positional parameters that have no meaning to it. A better script is:

 #!/command/execlineb
 elgetpositionals
 foreground { echo $0 $@ }
 emptyenv -P
 prog $@

which will run prog with the same environment as the script's caller.

Substituting positional parameters without touching the environment

Most of the time, you just need to substitute the positional parameters in your execline script, and don't need to go through the whole elgetpositionals and emptyenv chain. execline comes with an integrated substitution mechanism, that does not touch the environment at all: the -S n option.

Scripts beginning with:

#!/command/execlineb -Sn
foobar...

are equivalent to:

#!/command/execlineb
elgetpositionals -Pn
emptyenv -P
foobar...

So, to summarize, from most efficient (but less flexible) to least efficient (but more flexible):

  • Use execlineb -P if you don't need positional parameters at all; for instance, in s6 or runit run scripts.
  • Use execlineb -Sn if you need only simple positional parameter substitution in your script - no shift or elgetopt, no importas 1 1.
  • Use execlineb -p, then elgetpositionals if you don't mind overwriting the current stack of positional parameters.
  • Use execlineb, then elgetpositionals, then emptyenv -P if you need the full power of positional parameter handling.
execline-2.9.4.0/doc/el_semicolon.html000066400000000000000000000074031452216466500176020ustar00rootroot00000000000000 execline: block management

execline
Software
skarnet.org

Blocks

A command line (and thus an execline script) is one-dimensional. But a Unix execution flow can be two-dimensional: when two instructions are sequenced, for instance. In that case, we need a way to extract two command lines from one argv. That is precisely what blocks are made for.

execline commands that need more than one linear set of arguments use blocks. For instance, the foreground command needs to spawn a first process, then execute into a second one. It reads the command line for the first process from a block, and the command line for the second process from the rest of the argv. In the following script:

 #!/command/execlineb
 foreground { echo 1 } echo 2

echo 1 is read from a block and spawned; then echo 2 is executed.

execlineb syntax

In execlineb scripts, blocks are delimited by braces. They can be nested.

argv syntax

execlineb reads and parses the script, and converts it into an argv (a simple Unix command line) with a different syntax for blocks. In an argv, blocks are not delimited by braces; they are made of quoted arguments and terminated by an empty word (""). A quoted argument begins with a space. Nested blocks are represented by arguments being quoted several times, i.e. having several spaces in front of them; an empty word inside a block gets quoted too, i.e. it will be represented as a series of spaces.

Actually, the block-reading commands know nothing about braces; they only understand the "quoted arguments + empty word" syntax. So if you want to use foreground from your shell to sequence echo 1 and echo 2, you will have to write

 $ foreground ' echo' ' 1' '' echo 2

You do not really need to quote every argument inside a block in that simple case. The following command works as well:

 $ foreground echo 1 '' echo 2

However, this is bad practice, because it leads to a security hole: commands that perform substitution inside a block may produce empty words, which may modify your script's execution flow.

 $ define FOO '' foreground ' echo' ' ${FOO}' ' rm' ' -rf' ' /' '' echo blah

is safe, whereas

 $ define FOO '' foreground echo '${FOO}' rm -rf / '' echo blah

has very much unwanted results. (Don't try this at home.)

You can use the EXECLINE_STRICT environment variable to check proper block quoting. If that variable contains 1, commands that read blocks will print a warning message every time they find an unquoted argument inside a block. If that variable contains 2 or a bigger integer, commands will print an error message and die on unquoted arguments.
You can use execlineb's -w or -W switch to set EXECLINE_STRICT to 1 or 2.

execline-2.9.4.0/doc/el_substitute.html000066400000000000000000000227251452216466500200310ustar00rootroot00000000000000 execline: variable substitution

execline
Software
skarnet.org

Variable substitution

In a shell, when you write

 $ A='foobar' ; echo $A

the echo command is given the argument foobar. The foobar value has been substituted for the A variable.

Although execline maintains no state, and thus has no real variables, it provides such a substitution facility via substitution commands, namely:

A substitution command takes a key, i.e. a string (which can contain any character but $, { and }, although it is recommended to use only alphanumerical characters), and a way to compute a value.

Basics

  • If the substitution key is foo, then the substitution command will look for every occurrence of ${foo} or $foo in the rest of its argv. Note that ${foo}bar matches, but $foobar does not. To be safe, always use the syntax with braces, unless $foo is a word on its own.
  • Every match is then replaced with the value.

The simplest example is the following:

#!/command/execlineb
define FOO blah
echo $FOO

which will replace the FOO key with the blah value, then execute the echo command. So that script will print blah on stdout.

Quoting

execline allows you to write literal ${foo} constructs even when the foo variable is being substituted, thanks to a quoting mechanism. Brace (pun intended) yourself: the following is the most complex part of the whole language.

Rationale

If we want to be able to have a literal ${foo}, then:

  • The ${foo} sequence will mean one of two things: be substituted, or don't be substituted.
  • The default (unquoted) action should be: substitute.
  • A sequence that means "do not substitute" should be able to appear literally. The quote character should also be able to appear literally before a sequence that means "substitute". (Tricky, eh?)
  • There should be as few quote characters as possible, to avoid shell-like quoting nightmares.

Syntax

Rule:

  • The backslash (\) is a quote character for substitution commands.
  • The following rule applies only if the foo key is explicitly used in a substitution command. If no command tries to substitute anything for foo, sequences like ${foo} and preceding backslashes are left untouched.
  • (Substitute.) If ${foo} is preceded by 2*n backslashes (an even number), the whole sequence will be replaced with n backslashes, followed by the substituted value.
  • (Do not substitute.) If ${foo} is preceded by 2*n+1 backslashes (an odd number), the whole sequence will be replaced with n backslashes, followed by the literal ${foo}.

And now, the catch: the execlineb launcher, as well as the shell, interprets backslashes as escape characters. To make a word that contains a backlash, you need to write two backslashes in your execline script or shell command line. That means that the whole number of backslashes you must write before your ${foo} sequence must be doubled for the substitution command to read the proper number of backslashes and perform its work correctly.
Once you keep that in mind, the quoting rule is logical.

Example

The quoting rule is best illustrated with the following example, where the A key is substituted, and the $B sequences mean nothing special.

#!/command/execlineb
define A val
foreground { echo $A \\$A \\\\$A \\\\\\$A \\\\\\\\$A \\\\\\\\\\$A }
             echo $B \\$B \\\\$B \\\\\\$B \\\\\\\\$B \\\\\\\\\\$B

prints

val $A \val \$A \\val \\$A
$B \$B \\$B \\\$B \\\\$B \\\\\$B

Phew.

Value transformations

A value can go through several transformations before it is substituted. It can be crunched, chomped, and/or split.

Substitution of split values

A split value for FOO means that a word containing ${FOO} will be replaced by zero, one, or (usually) more than one word. The value actually means a list of values.

The rule is: substituting a list of values (v1, v2, ...) for a key A is the same as listing the substitutions of every value vi for A.
For instance,

#!/command/execlineb
define -s FOO "v1 v2 v3" echo prefix-${FOO}-postfix

will substitute three values for $FOO: v1, v2 and v3. So the echo command will be called with three arguments: prefix-v1-postfix, prefix-v2-postfix, and prefix-v3-postfix.

(Implementation note: the fact that word prefixes are kept is what makes execline's subtitutions secure. Blocks are implemented via prefix space characters; a substitution occurring inside a block will always produce words beginning with the right amount of spaces, thus substituted values cannot prematurely terminate a block.)

Recursive substitutions

A direct consequence of that rule is that substitutions will be performed recursively if more than one key appears in one word and the values for those keys are split. Parallel substitutions are performed from left to right. For instance, in

#!/command/execlineb
define -s B "1 2 3" echo ${B}x${B}

the ${B}x${B} word will be replaced with nine words: 1x1, 1x2, 1x3, 2x1, 2x2, 2x3, 3x1, 3x2, and 3x3, in that order.
Here is an example with two distinct substitutions in parallel:

#!/command/execlineb
multisubstitute
{
  define -s A "a b c d"
  define -s B "1 2 3"
}
echo ${A}x${B}

The ${A}x${B} word will be replaced with twelve words: ax1, ax2, ax3, bx1, bx2, bx3, cx1, cx2, cx3, dx1, dx2, and dx3, in that order. You can check that the order of the define directives in multisubstitute does not matter.

If the left-to-right order does not suit you, then you should perform serial substitutions. For instance, the previous script can be replaced with

#!/command/execlineb
define -s B "1 2 3"
define -s A "a b c d"
echo ${A}x${B}

and will substitute ${B} first, then ${A}. So it will print

ax1 bx1 cx1 dx1 ax2 bx2 cx2 dx2 ax3 bx3 cx3 dx3

in that order.

Not for the faint of heart

If you think you have mastered the art of execline substitution, then you can try to do better than these people:

execline-2.9.4.0/doc/el_transform.html000066400000000000000000000153411452216466500176250ustar00rootroot00000000000000 execline: value transformation

execline
Software
skarnet.org

Value transformation

You can apply 3 kinds of transformations to a value which is to be substituted for a variable: crunching, chomping and splitting. They always occur in that order.

Delimiters

The transformations work around delimiters. Delimiters are the semantic bounds of the "words" in your value. You can use any character (except the null character, which you cannot use in execline scripts) as a delimiter, by giving a string consisting of all the delimiters you want as the argument to the -d option used by substitution commands. By default, the string " \n\r\t" is used, which means that the default delimiters are spaces, newlines, carriage returns and tabs.

(The forstdin command is a small exception: by default, it only recognizes newlines as delimiters.)

Crunching

You can tell the substitution command to merge sets of consecutive delimiters into a single delimiter. For instance, to replace three consecutive spaces, or a space and 4 tab characters, with a single space. This is called crunching, and it is done by giving the -C switch to the substitution command. The remaining delimiter will always be the first in the sequence. Crunching is off by default, or if you give the -c switch.

Crunching is mainly useful when also splitting.

Chomping

Sometimes you don't want the last delimiter in a value. Chomping deletes the last character of a value if it is a delimiter. It is requested by giving the -n switch to the substitution command. You can turn it off by giving the -N switch. It is off by default unless mentioned in the documentation page of specific binaries. Note that chomping always happens after crunching, which means you can use crunching+chomping to ignore, for instance, a set of trailing spaces.

Splitting

In a shell, when you write

 $ A='foo bar' ; echo $A

the echo command is given two arguments, foo and bar. The $A value has been split, and the space between foo and bar acted as a delimiter.

If you want to avoid splitting, you must write something like

 $ A='foo bar' ; echo "$A"

The doublequotes "protect" the spaces. Unfortunately, it's easy to forget them and perform unwanted splits during script execution - countless bugs happen because of the shell's splitting behaviour.

execline provides a splitting facility, with several advantages over the shell's:

  • Splitting is off by default, which means that substitutions are performed as is, without interpreting the characters in the value. In execline, splitting has to be explicitly requested by specifying the -s option to commands that perform substitution.
  • Positional parameters are never split, so that execline scripts can handle arguments the way the user intended to. To split $1, for instance, you have to ask for it specifically:
    #!/command/execlineb -S1
    define -sd" " ARG1S $1
    blah $ARG1S
    
    and $ARG1S will be split using the space character as only delimiter.
  • Any character can be a delimiter.

How it works

  • A substitution command can request that the substitution value be split, via the -s switch.
  • The splitting function parses the value, looking for delimiters. It fills up a structure, marking the split points, and the number n of words the value is to be split into.
    • A word is a sequence of characters in the value terminated by a delimiter. The delimiter is not included in the word.
    • If the value begins with x delimiters, the word list will begin with x empty words.
    • The last sequence of characters in the value will be recognized as a word even if it is not terminated by a delimiter, unless you have requested chomping and there was no delimiter at the end of the value before the chomp operation - in which case that last sequence will not appear at all.
  • The substitution rewrites the argv. A non-split value will be written as one word in the argv; a split value will be written as n separate words.
  • Substitution of split values is performed recursively.

Decoding netstrings

Netstrings are a way to reliably encode strings containing arbitrary characters. execline takes advantage of this to offer a completely safe splitting mechanism. If a substitution command is given an empty delimiter string (by use of the -d "" option), the splitting function will try to interpret the value as a sequence of netstrings, every netstring representing a word. For instance, in the following command line:

 $ define -s -d "" A '1:a,2:bb,0:,7:xyz 123,1: ,' echo '$A'

the echo command will be given five arguments:

  • the "a" string
  • the "bb" string
  • the empty string
  • the "xyz 123" string
  • the " " string (a single space)

However, if the value is not a valid sequence of netstrings, the substitution command will die with an error message.

The dollarat command, for instance, can produce a sequence of netstrings (encoding all the arguments given to an execline script), meant to be decoded by a substitution command with the -d "" option.

execline-2.9.4.0/doc/elgetopt.html000066400000000000000000000047121452216466500167550ustar00rootroot00000000000000 execline: the elgetopt command

execline
Software
skarnet.org

The elgetopt program

elgetopt performs getopt-style parsing on the arguments to an execline script.

Interface

     elgetopt [ -D default ] optstring prog...
  • elgetopt expects to find a valid number n of arguments in the # environment variable, and n+1 environment variables 0, 1, ..., n. It exits 100 if it is not the case.
  • elgetopt pushes environment variables starting with ELGETOPT_. To get the previous values back, use emptyenv -o.
  • elgetopt looks into 1, 2... for options, as specified by optstring, which is a standard getopt string.
  • If the -c switch is recognized, elgetopt sets the ELGETOPT_c environment variable. The value of that variable is the argument to the -c switch if it has one, and 1 (or default if given) otherwise.
  • After setting all recognized options, elgetopt makes new #, 1, 2... "positional parameters" with what remains.
  • elgetopt then execs into prog....

Options

  • -D default : use default as the value for the ELGETOPT_c environment variable if there is no argument to the -c switch. Default is 1. The value is the same for all the options defined by elgetopt.

Notes

  • GNU-style options are not supported.
execline-2.9.4.0/doc/elgetpositionals.html000066400000000000000000000065241452216466500205220ustar00rootroot00000000000000 execline: the elgetpositionals command

execline
Software
skarnet.org

The elgetpositionals program

elgetpositionals substitutes the positional parameters of an execline script.

Interface

     elgetpositionals [ -P sharp ] prog...
  • elgetpositionals reads the number n of "positional parameters" in the # environment variable. If that variable is not set or does not contain a valid n, elgetpositionals exits 100.
  • elgetpositionals performs some substitutions in parallel on prog...:
    • key: #, value: n
    • key: 0, value: the value of the 0 environment variable
    • key: 1, value: the value of the 1 environment variable
    • ... and so on until n (or sharp if it is greater than n). Those values are never transformed.
    • key: @, value: all values of the variables from 1 to n. This value is split into n words.
    If a variable between 0 and n does not exist, elgetpositionals exits 100.

Options

  • -P sharp : substitute at least sharp+1 positional parameters, from 0 to max(n, sharp). If n<sharp, positional parameters between n+1 and sharp are replaced with the empty string. Not having the -P switch is equivalent to having -P 0.

Notes

  • A typical argument-taking execline script will often begin this way:
     #!/command/execlineb
     elgetopt optstring
     elgetpositionals
     prog...
    
  • If you are performing other substitutions that do not depend on the positional parameters, think about replacing the elgetpositionals call with a multisubstitute call containing the elgetpositionals directive.
  • If you are going to use the shift command, it is best to use importas to substitute the first positional parameters, then use shift, then elgetpositionals. That way, $@ will correctly be replaced by the remaining arguments. More generally, you should try to use elgetpositionals as late as possible.
  • Use execlineb's -S switch instead of elgetpositionals whenever you can. It is more efficient.
execline-2.9.4.0/doc/elglob.html000066400000000000000000000050231452216466500163720ustar00rootroot00000000000000 execline: the elglob command

execline
Software
skarnet.org

The elglob program

elglob performs globbing on a pattern, then executes another program.

Interface

     elglob [ -v ] [ -w ] [ -s ] [ -m ] [ -e ] [ -0 ] variable pattern prog...
  • elglob performs globbing on pattern.
  • It then performs variable substitution on prog..., using variable as key and the result of the globbing as value. The value is always split: it contains as many words as they are matches for the globbing pattern.
  • elglob then execs into the modified prog....

Options

  • -v : verbose. If there is a problem while globbing, print a warning message on stderr.
  • -w : strict. If there is a problem while globbing, die immediately. This is harsh - you probably don't need that option.
  • -s : sort the matches. By default, the results are left unsorted.
  • -m : mark. Append a slash to each word that corresponds to a directory.
  • -e : no escape. Treat backslashes in pattern literally; do not allow quoting of metacharacters in pattern via backslashes. Warning: the execlineb launcher uses the backslash as their own escape character - if you want a backslash to be passed to elglob, do not forget to double it.
  • -0 : null globbing. By default, if pattern matches nothing, it will be substituted as is (verbatim in one word). With this option, if pattern matches nothing, it will be properly substituted as zero word.
execline-2.9.4.0/doc/eltest.html000066400000000000000000000165611452216466500164370ustar00rootroot00000000000000 execline: the eltest program

execline
Software
skarnet.org

The eltest program

eltest evaluates an expression and indicates the result via its exit status.

Interface

     eltest expression...

eltest acts as the generic POSIX test utility, but it diverges from the specification on how it parses ambiguous arguments, see below.

eltest supports all the standard test operands, plus all the extensions from GNU test, plus a few extensions from the test builtin from bash. The extensions to POSIX test are listed below.

eltest accepts an arbitrary number of arguments and, if the expression is valid, always returns the result of the expression no matter how complex it is.

Exit codes

  • 0: the test is true
  • 1: the test is false
  • 100: wrong usage
  • 101: internal error (should never happen, warrants a bug-report)
  • 111: system call failure

Posixness

eltest is not suitable as a Single Unix test program, due to the way it disambiguates between arguments and operators, see below. However, if you never use arguments that start with a backslash, or that have the same name as an existing operator, then eltest exhibits the same behaviour as test.

Extensions to POSIX

  • expr1 -a expr2 : tests whether expr1 and expr2 are true. If expr1 is false, then expr2 is not evaluated.
  • expr1 -o expr2 : tests whether expr1 or expr2 is true. If expr1 is true, then expr2 is not evaluated.
  • -k file : tests whether file has the sticky bit.
  • -O file : tests whether file is owned by the effective uid of the current process.
  • -U file : same.
  • -G file : tests whether file's gid is the effective gid of the current process.
  • -N file : tests whether file exists and has been modified since it was last read.
  • file1 -nt file2 : tests whether file1 has a (strictly) newer modification date than file2.
  • file1 -ot file2 : tests whether file1 has a (strictly) older modification date than file2.
  • file1 -ef file2 : tests whether file1 and file2 are physically the same file (same device and inode numbers).
  • -v var : tests whether the var variable is defined in the current environment.
  • string =~ pattern : tries to match string against extended regular expression pattern. True if any part of string matches pattern; in order to match whole strings, you must anchor pattern with ^ and $ markers.

Argument disambiguation

Unlike test, which has different fixed syntax trees depending on the number of arguments it receives and has undefined behaviour when called with more than 5 arguments, eltest accepts any number of arguments and builds its syntax trees on the fly. This means that expressions such as -n = -n cannot be automatically disambiguated: eltest does not know that there are 3 arguments, so when it reads the first -n it assumes that it is a unary operator, then when it reads = it assumes it is the argument to -n, then when it reads the second -n it exits with a syntax error.

Doing otherwise would result in a combinatory explosion of possible syntax trees, making it easy for users to trigger unbounded RAM consumption, and turning a simple utility into a programming nightmare. This is why POSIX test is so restricted. But we don't want the same restrictions.

So, instead, eltest provides the user with a mechanism to make sure that operands are never mistaken for operators:

  • A word that looks like an operator will always be interpreted like an operator. So, expressions like -n = -n will result in a syntax error, because the first -n will never be understood as data for the = operator.
  • A word that starts with a \ (backslash) will always be interpreted like data, never like an operator, and the backslash will be removed. This means: \-n = \-n is a valid expression testing the equality between the strings -n and -n.
    • Be aware that execline as well as the shell use one backlash for their own unquoting mechanism, so when using backslashes in an execline or shell script, they must be doubled. You would probably need to type something like \\-n = \\-n.
  • So, if your script tests equality between $a and $b, and there's a possiblity that the contents of these variables look like eltest operators, the proper syntax would be: eltest \\${a} = \\${b}.

Note that these details are irrelevant to a huge majority of eltest use cases, because most of the time users only need a simple test such as eltest -r ${file} to check that $file is readable, and there's no possible ambiguity. So, don't panic over this.

Notes

  • eltest is a replacement for the ill-named, and now deprecated, s6-test program, part of the (just as ill-named) s6-portable-utils package. It is too valuable a utility to be part of a marginal package, and has nothing to do with s6.
execline-2.9.4.0/doc/emptyenv.html000066400000000000000000000037441452216466500170050ustar00rootroot00000000000000 execline: the emptyenv program

execline
Software
skarnet.org

The emptyenv program

emptyenv empties the current environment, or cleans it up; then executes a program.

Interface

     emptyenv [ -p ] prog...
     emptyenv -c prog...
     emptyenv [ -o ] [ -P ] prog...

By default, emptyenv unsets all environment variables, then execs into prog with its arguments. Options control which environment variables are unset.

Options

  • -p : keep the PATH environment variable.
  • -c : clean up. Do not empty the environment. Instead, remove every variable used internally by the execline programs, to avoid any interference with or information leakage to external programs.
  • -o : pop environment variables starting with ELGETOPT_. You might want to do this before executing a final program from a script that uses elgetopt.
  • -P : pop environment variables starting with #, 0 to 9, and EXECLINE_. You might want to do this before executing a final program from a script launched by execlineb.
execline-2.9.4.0/doc/envfile.html000066400000000000000000000101141452216466500165530ustar00rootroot00000000000000 execline: the envfile program

execline
Software
skarnet.org

The envfile program

envfile reads a file containing variable assignments, adds the variables to the environment, then executes a program.

Interface

     envfile [ -i | -I ] file prog...

envfile reads file and adds the key-value pairs defined in file to the environment. Then it execs into prog..., i.e. the rest of its command line, with the modified environment.

Exit codes

  • 1: syntax error in file
  • 100: wrong usage
  • 111: system call failed
  • 126: execve() on prog failed (unknown reason)
  • 127: execve() on prog failed (prog could not be found)

0 is not listed because on success, envfile does not exit: it execs into prog.

Options

  • -i : strict. If file does not exist, exit 111 with an error message. This is the default.
  • -I : loose. If file does not exist, exec into prog without modifying the environment.

File syntax

file is a text file containing lines of the form key = value. Whitespace is permitted before and after key, and before or after value.

Empty lines, or lines containing only whitespace, are ignored. Lines beginning with # (possibly after some whitespace) are ignored (and typically used for comments). Leading and trailing whitespace is stripped from values; but a value can be double-quoted, which allows for inclusion of leading and trailing whitespace.

A non-commented line that ends with a backslash ("\") is concatenated with the following one, and the newline character is ignored. If a backslashed newline happens before the start of a value, then the whitespace at the beginning of the new line will be part of the value (i.e. leading whitespace on a new line is not stripped).

C escapes, including hexadecimal and octal sequences, are supported in quoted values. Unicode codepoint sequences are not supported. It is possible to include a newline in a quoted value by using \n; but including newlines in environment variables is not recommended.

If value is empty, key is still added to the environment, with an empty value. If you do not want key to be added to the environment at all, comment out the line. envfile does not offer a way to remove variables from the environment.

The envfile format is largely compatible with systemd's EnvironmentFile format, which allows for the reuse of such files outside of systemd.

Notes

  • If file is - then envfile reads and parses its standard input instead. To read a file literally named -, you can use ./- for instance.
  • The variables that can be defined with envfile are purposefully restricted. If you need more expressive power for your variable names, or for your values, you should use an envdir instead: see s6-envdir.
execline-2.9.4.0/doc/exec.html000066400000000000000000000032731452216466500160570ustar00rootroot00000000000000 execline: the exec program

execline
Software
skarnet.org

The exec program

exec executes the command line it is given.

Interface

     exec [ -c ] [ -l ] [ -a argv0 ] prog...

exec execs into prog.... It does nothing else.
Without options, exec can be seen as the execline NOP.

Options

  • -c : empty the environment. prog is executed with no environment variables. Warning: prog will run with an empty PATH, so make sure it does not rely on it.
  • -l : login. Prepends prog's argv[0] with a dash.
  • -a argv0 : argv0. Replace prog's argv[0] with argv0. This is done before adding a dash, if the -l option is also present.

The exec command, along with its options, is designed to emulate the standard exec shell builtin, which replaces the shell with the command it is given.

execline-2.9.4.0/doc/execline-cd.html000066400000000000000000000033151452216466500173100ustar00rootroot00000000000000 execline: the execline-cd command

execline
Software
skarnet.org

The execline-cd program

execline-cd changes the current working directory to a given directory, then executes a program.

Interface

     execline-cd dir prog...

execline-cd performs a chdir() system call on dir, then execs into prog....

Notes

  • By default, execline-cd can also be invoked as cd: there is a cd program which is a symbolic link to execline-cd.
  • When execline has been configured with the --enable-pedantic-posix option, the cd binary is a symbolic link to the posix-cd binary instead, so a cd command in an execline script will invoke posix-cd instead of execline-cd.
  • Existing scripts that call cd will keep working no matter the chosen configuration.
execline-2.9.4.0/doc/execline-shell.html000066400000000000000000000034211452216466500200270ustar00rootroot00000000000000 execline: the execline-shell script

execline
Software
skarnet.org

The execline-shell script

execline-shell executes $HOME/.execline-shell if available (or /bin/sh otherwise) with the arguments it is given.

Interface

     /etc/execline-shell
  • execline-shell transforms itself into ${HOME}/.execline-shell $@.
  • ${HOME}/.execline-shell must be readable and executable by the user. It must exec into an interactive shell with $@ as its argument.

Notes

  • execline-shell is meant to be used as the SHELL environment variable value. It allows one to specify their favourite shell and shell configuration in any language, since the ${HOME}/.execline-shell file can be any executable program. ${HOME}/.execline-shell can be seen as a portable .whateverrc file.
  • As an administrator-modifiable configuration file, execline-shell is provided in execline's examples/etc/ subdirectory, and should be copied by the administrator to /etc.
execline-2.9.4.0/doc/execline-startup.html000066400000000000000000000043061452216466500204250ustar00rootroot00000000000000 execline: the execline-startup script

execline
Software
skarnet.org

The execline-startup script

execline-startup performs some system-specific login initialization, then executes ${HOME}/.execline-loginshell.

Interface

     /etc/execline-startup
  • execline-startup sets the SHELL environment variable to /etc/execline-shell. It then performs some system-specific initialization, and transforms itself into ${HOME}/.execline-loginshell $@ if available (and /etc/execline-shell otherwise).
  • ${HOME}/.execline-loginshell must be readable and executable by the user. It must exec into $SHELL $@.

Notes

  • execline-startup is an execlineb script; hence, it is readable and modifiable. It is meant to be modified by the system administrator to perform system-specific login-time initialization.
  • As a modifiable configuration file, execline-startup is provided in execline's examples/etc/ subdirectory, and should be copied by the administrator to /etc.
  • execline-startup is meant to be used as a login shell. System administrators should manually add /etc/execline-startup to the /etc/shells file. The /etc/execline-startup file itself plays the role of the /etc/profile file, and ${HOME}/.execline-loginshell plays the role of the ${HOME}/.profile file.
execline-2.9.4.0/doc/execline-umask.html000066400000000000000000000027371452216466500200510ustar00rootroot00000000000000 execline: the execline-umask command

execline
Software
skarnet.org

The execline-umask program

execline-umask sets the umask (file creation mask), then executes a program.

Interface

     execline-umask mask prog...

execline-umask sets the current umask to mask, then execs into prog....

Notes

  • By default, at execline installation time, a umask symbolic link is created, pointing to execline-umask.
  • When execline has been configured with the --enable-pedantic-posix option, the umask symbolic link points to the posix-umask binary instead.
  • Existing execline scripts calling umask will keep working no matter the chosen configuration.
execline-2.9.4.0/doc/execline.html000066400000000000000000000072731452216466500167330ustar00rootroot00000000000000 execline: the execline program

execline
Software
skarnet.org

The execline program

The execline program is only available when the --enable-multicall option has been given to the configure program at build time. In this configuration, execline is a multicall binary implementing the functionality of all the programs in the execline package; and the other programs, instead of being executables of their own, are symbolic links to the execline binary.

Interface

     execline subcommand subcommand_arguments...

execline will run the subcommand with its arguments. For instance, execline cd / ls will run the equivalent of the cd program, so this command will list the contents of the / directory.

Alternatively, if execline is called with the name of an existing command, it will run the equivalent of that command. For instance, if the /usr/bin/cd file is a (hard or symbolic) link to the execline binary, /usr/bin/cd / ls will list the contents of the / directory.

Notes on the multicall configuration

The --enable-multicall option is a user-requested feature to save disk space. Its goal is purely to save disk space; functionality-wise, the execline package should be the exact same whether it has been built with --enable-multicall or not. That means: any execline script should work the exact same way.

Multicall binaries have a number of issues, most of them hidden from regular users. One user-visible issue is that their behaviour changes depending on how they are called, which is not good practice (it breaks naming agnosticism) despite being common in traditional Unix. Other, more important issues are only visible to software authors and maintainers: for instance, they make it difficult to add functionality to a software package without inadvertently blowing up the amount of RAM used by the software, and they encourage bad engineering practices to work around specific problems created by this configuration.

I am not a fan of multicall binaries at all.

However, it just so happens that the execline package already was a good candidate for a multicall configuration, and several users had been asking for it (and complaining about the amount of disk space that the traditional execline package uses). So I did an experiment, and it turned out that a multicall execline binary does save a huge amount of space. Depending on your shared/static library configuration and your libc, the gain in disk space on Linux can range from 66% to 87%! The results were contrary to my expectations — and simply too good to pass up.

So now, the multicall configuration is supported for execline. Do not expect anything similar for other skarnet.org packages such as s6, because they're not as good candidates and it would require a tremendous amount of work for less benefit.

execline-2.9.4.0/doc/execlineb.html000066400000000000000000000253471452216466500170770ustar00rootroot00000000000000 execline: the execlineb command

execline
Software
skarnet.org

The execlineb program

execlineb reads and executes a script.
It is a command launcher: it reads a file, turns that file into a command line, then executes into that command line.

Interface

     execlineb [ -q | -w | -W ] [ -p | -P | -S nmin | -s nmin ] [ -e ] -c script [ args... ]

or

     execlineb [ -q | -w | -W ] [ -p | -P | -S nmin | -s nmin ] [ -e ] scriptfile [ args... ]

or in an executable file:

#!/command/execlineb [ -qwWpPSnmin ]
script

Parsing phase.

  • execlineb reads and parses the script it is given. It exits 100 on a syntax error and 111 on a temporary error. It makes an argv, i.e. a system command line, with the parsed script. If the argv is empty, execlineb exits 0.

Environment management phase.

  • Pushing the current stack frame. If none of the -p, -P, -S or -s options are set: execlineb pushes the current positional parameters, i.e. environment variables that start with #, 0, 1, ..., 9. To get the previous values back, use emptyenv -P.
  • Setting the new stack frame. If none of the -P, -S or -s options are set:
    • execlineb sets the # environment variable to the number n of args it is given.
    • It sets the 0 environment variable to the name of the script - or to the execlineb invocation name if the -c option is used.
    • It sets the 1, 2, ... n environment variables to the different args.

Execution phase.

  • execlineb executes into the argv it has built from the script. There is only one command line for the whole script: the execlineb binary is a launcher, whose sole purpose is to execute into that command line. It does not stay in memory like a traditional interpreter would.

Options

  • -e : this option is ignored. This is meant to support the use of execlineb in conjuction with programs that invoke $SHELL -ec script; the effect of /bin/sh -e can be natively replicated in execline scripts if you use the if command instead of the foreground command.
  • -c script : execute script, do not look for a file.

See below for the other options.

Syntax of scripts

An execlineb script is a string that must not contain the null character. execlineb parses it and divides it into words. The parser recognizes the following components:

  • whitespace is defined as spaces, tabs, newlines and carriage returns. Words are always separated by whitespace.
  • A quoted string begins with a doublequote (") and ends with another doublequote. Quoted doublequotes must be prefixed by a backslash (\). Quoted strings always evaluate to exactly one word. For instance, "" evaluates to the empty word.
  • The \a, \b, \t, \n, \v, \f, and \r sequences are recognized in quoted strings, and are converted to the ASCII numbers 7, 8, 9, 10, 11, 12 and 13 respectively.
  • Inside a quoted string, backslashed newlines disappear completely.
  • \0xab sequences are recognized in quoted strings and evaluate to ASCII hexadecimal number ab.
  • \0abc sequences are recognized in quoted strings and evaluate to ASCII octal number abc. abc must not be greater than 377, or evaluate to 0.
  • \abc sequences are recognized in quoted strings and evaluate to ASCII decimal number abc. a must not be zero. abc must not be greater than 255, or evaluate to 0.
  • A comment starts with a # and ends with the line. Comments are not recognized inside quoted strings.
  • Anything else is an unquoted string, that can evaluate to zero or more words.
  • Any character can be escaped in unquoted strings by prepending it with a backslash. It works the same way in quoted strings, except for the special sequences described above.
  • As a special case, an unquoted backslash at the end of a line, or at the end of the input, is ignored. This is to make it easier to copy execline fragments from a shell script.

You can see an example of distinct execlineb components here.

In addition to that simple lexing, execlineb performs the following higher-level parsing:

  • A word consisting of a single opening brace ({) increments an internal level counter, blevel, and disappears from the argv. Quoted open braces do not have that behaviour.
  • A word consisting of a single closing brace (}) decrements blevel, and is replaced with the empty word. Quoted closing braces do not have that behaviour.
  • If execlineb finds that braces are unmatched (i.e. blevel goes below 0 during the parsing, or is not 0 at the end of the script), it exits 100 with an error message.
  • execlineb automatically quotes blocks. Which means that every time it finds a word, it prepends it with blevel spaces.

For proper execution, the sequence of words must follow the execline grammar.

Options for block syntax checking

External execline commands that read blocks, like foreground, use the EXECLINE_STRICT environment variable: if it is set to 1, they will print a warning message on stderr if they find their blocks not to be properly quoted. If it is set to 2, they will also die. If it is set to 0, or unset, they won't complain at all.

Normally the EXECLINE_STRICT environment variable is inherited from the caller. You can force it unset, set to 1, or set to 2 by giving respectively the -q, -w or -W option to execlineb.

The EXECLINE_STRICT variable (as well as the -q, -w and -W options to execlineb) will also modify the behaviour of the -S nmin and -s nmin options when execlineb is called with less than nmin positional parameters:

  • If EXECLINE_STRICT is 0: the script will run silently, and missing positional parameters, up to nmin, will be substituted with the empty word.
  • If EXECLINE_STRICT is 1 or unset: same, but the script will print a warning message rather than run silently.
  • If EXECLINE_STRICT is 2: the script will exit with an error message.

Options for environment management

Normally, execline scripts are reentrant: environment variables potentially overwritten by execlineb, such as # or 0, are pushed. This is the standard, safe behaviour. Nevertheless, it is rather costly, and may be unneeded for small scripts: for those cases, execline comes with two options that bypass the environment management. Be warned that the purpose of these options is optimization, and you should not use them if you're not familiar with the way execlineb uses the environment to store positional parameters. Alternatively, there's also an integrated substitution mechanism that doesn't make use of the environment at all.

  • The -p option will bypass the push phase: the current frame of positional parameters will be overwritten. The script will not be reentrant.
  • The -P option will bypass positional parameter handling completely: the environment will not be pushed, and positional parameters will be ignored. execlineb -P -c "script" is equivalent to, but more efficient than, execlineb -c "emptyenv -P script". You should use the -P option only in standalone scripts that take no arguments, such as s6's or runit's run scripts.
  • The -S nmin option will substitute the positional parameters - up to at least nmin - but will not push nor set environment variables. execlineb -S3 -c "script" is equivalent to, but more efficient than, execlineb -c "elgetpositionals -P3 emptyenv -P script". See the details.
  • The -s nmin option behaves just like the -S option, except that it defines $@ as the rest of the command line after nmin arguments have been removed.

Current limitations

execlineb builds and executes a unique argv with the script: hence scripts are subject to OS-dependent limitations such as the kernel buffer size for argv and envp - at least 64 kB on most systems. This means that execlineb cannot execute arbitrarily large scripts. Be careful with deeply nested scripts too: without the -p/-P/-S/-s option, each execlineb invocation uses up some space in the environment.

execline-2.9.4.0/doc/exit.html000066400000000000000000000021271452216466500161010ustar00rootroot00000000000000 execline: the exit program

execline
Software
skarnet.org

The exit program

exit exits with a given exit code.

Interface

     exit [ n ]

exit exits with the exit code n, or 0 if n is not given (in which case it's the same as true). If n is not a number, exit exits 100.

Notes

exit is a standard shell builtin, with the same function.

execline-2.9.4.0/doc/exitcodes.html000066400000000000000000000100741452216466500171170ustar00rootroot00000000000000 execline: exit codes

execline
Software
skarnet.org

How to propagate exit codes up a process dynasty

Say we have a parent process P, child of a grandparent process G, spawning a child process C and waiting for it. Either C dies normally with an exit code from 0 to 255, or it is killed by a signal. How can we make sure that P reports to G what happened to C, with as much precision as possible?

The problem is, there's more information in a wstat (the structure filled in by waitpid()) than a process can report by simply exiting. P could exit with the same exit code as C, but then what should it do if C has been killed by a signal?

An idea is to have P kill itself with the same signal that killed C. But that's actually not right, because P itself could be killed by a signal from another source, and G needs that information. "P has been killed by a signal" and "C has been killed by a signal" are two different pieces of information, so they should not be reported in the same way.

So, any way you look at it, there is always more information than we can report.

Shells have their own convention for reporting crashes, but since any exit code greater than 127 is reported as is, the information given by the shell is unreliable: "child exited 129" and "child was killed by SIGHUP" are indistinguishable. When shells get nested, all bets are off - the information conveyed by exit codes becomes devoid of meaning pretty fast. We need something better.

execline's solution

execline commands such as if, that can report a child's exit code, proceed that way when they're in the position of P:

  • If C was killed by a signal: P exits 128 plus the signal number.
  • If C exited 128 or more: P exits 128.
  • Else, P exits with the same code as C.

Rationale:

  • 128+ exit codes are extremely rare and should report really problematic conditions; commands usually exit 127 or less. If C exits 128+, it's more important to convey the information "something really bad happened, but the C process itself was not killed by a signal" than the exact nature of the event.
  • Commands following that convention can be nested. If P exits 129+, G knows that C was killed by a signal. If G also needs to report that to its parent, it will exit 128: G's parent will not know the signal number, but it will know that P reported 128 or more, so either C or a scion of C had problems.
  • Exact information is reported in the common case.

Summary of common exit codes for execline programs

  • 0: success. This code is rarely encountered, because most execline programs chainload into something else when they succeed, instead of exiting 0.
  • 100: wrong usage
  • 111: system call failed
  • 126: unable to chainload into another program (any other error than ENOENT)
  • 127: unable to chainload into another program (executable not found)
execline-2.9.4.0/doc/export.html000066400000000000000000000022721452216466500164520ustar00rootroot00000000000000 execline: the export program

execline
Software
skarnet.org

The export program

export sets an environment variable to a given value, then executes a program.

Interface

     export var value prog...

export sets the var environment variable to the string value, then execs into prog with its arguments.

  • var must be given without a dollar!
  • var must not contain the character = .
execline-2.9.4.0/doc/fdblock.html000066400000000000000000000031431452216466500165330ustar00rootroot00000000000000 execline: the fdblock program

execline
Software
skarnet.org

The fdblock program

fdblock sets or unsets the O_NONBLOCK flag on a given file descriptor (which makes reading or writing non-blocking or blocking), then executes a program.

Interface

     fdblock [ -n ] fd prog...

fdblock makes the file descriptor number fd blocking, no matter what its previous state was. It then execs into prog with its arguments.

Options

  • -n : non-blocking. Sets fd to non-blocking mode instead of blocking mode. If used on stdin (0) or stdout (1), this option will make a lot of command-line programs behave improperly, because most simple command-line programs only support blocking stdin and stdout. Make sure you know what you are doing.

Notes

  • fdblock has no portable shell equivalent.
execline-2.9.4.0/doc/fdclose.html000066400000000000000000000022301452216466500165420ustar00rootroot00000000000000 execline: the fdclose program

execline
Software
skarnet.org

The fdclose program

fdclose closes a given file descriptor, then executes a program.

Interface

     fdclose fd prog...

fdclose closes the file descriptor number fd, then execs into prog with its arguments.

Notes

  • fdclose n prog... is roughly equivalent to sh -c 'exec prog... n<&-'
execline-2.9.4.0/doc/fdmove.html000066400000000000000000000040221452216466500164040ustar00rootroot00000000000000 execline: the fdmove program

execline
Software
skarnet.org

The fdmove program

fdmove moves or copies a given file descriptor, then executes a program.

Interface

     fdmove [ -c ] fdto fdfrom prog...

fdmove moves the file descriptor number fdfrom, to number fdto, then execs into prog with its arguments. If fdto is open, fdmove closes it before moving fdfrom to it.

Options

  • -c : duplicate fdfrom to fdto instead of moving it; do not close fdfrom.

Notes

  • fdmove a b prog... is roughly equivalent to sh -c 'exec prog... a>&b b<&-'. It means: if you write to fd a now, it will have the same effect as writing to fd b beforehand, and you cannot write to fd b anymore.
  • fdmove -c a b prog... is roughly equivalent to sh -c 'exec prog... a>&b'. It means: you can now write to fd a, and also still write to fd b, and both will have the same effect as writing to fd b beforehand.
  • It also works with file descriptors that are open for reading!
execline-2.9.4.0/doc/fdreserve.html000066400000000000000000000044461452216466500171230ustar00rootroot00000000000000 execline: the fdreserve program

execline
Software
skarnet.org

The fdreserve program

fdreserve updates the environment with file descriptors that are guaranteed safe to use, then executes a program.

Interface

     fdreserve n prog...
  • fdreserve tries to reserve n file descriptors.
  • fdreserve sets the FD0, FD1, ..., FDn-1 environment variables: each FDi contains a valid file descriptor, that can be safely opened.
  • fdreserve then execs into prog with its arguments.

Common use

fdreserve can be used when you do not want to hardcode file descriptors in your scripts. For instance, to create a pipe, you could use:

 #!/command/execlineb
 fdreserve 2
 multisubstitute
 {
   importas fdr FD0
   importas fdw FD1
 }
 piperw $fdr $fdw
 prog...

Warning: fdreserve does not allocate descriptors, it merely returns descriptors that are free at the time it is run. A program like

 #!/command/execlineb
 fdreserve 3
 multisubstitute
 {
   importas fdr FD0
   importas fdw FD1
 }
 piperw $fdr $fdw
 fdreserve 1
 multisubstitute
 {
   importas oldfd FD2
   importas newfd FD0
 }
 prog...

may fail, because oldfd and newfd may be the same. To avoid that, you should make sure that all descriptors returned by fdreserve are actually allocated before calling fdreserve again. (Thanks to Paul Jarc for having spotted that case.)

execline-2.9.4.0/doc/fdswap.html000066400000000000000000000021501452216466500164100ustar00rootroot00000000000000 execline: the fdswap program

execline
Software
skarnet.org

The fdswap program

fdswap swaps two file descriptors, then executes a program.

Interface

     fdswap fd1 fd2 prog...

fdswap swaps file descriptors numbered fd1 and fd2, then execs into prog with its arguments.

Notes

  • fdswap has no portable shell equivalent.
execline-2.9.4.0/doc/forbacktickx.html000066400000000000000000000113231452216466500176000ustar00rootroot00000000000000 execline: the forbacktickx command

execline
Software
skarnet.org

The forbacktickx program

forbacktickx runs a program and uses its output as loop elements to run another program.

Interface

In an execlineb script:

     forbacktickx [ -E | -e ] [ -p | -o okcodes | -x breakcodes ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] variable { gen... } loop...
  • forbacktickx reads a block, gen..., and unquotes it.
  • It runs gen... as a child process. gen's output must not contain a null character.
  • It reads gen's output as it needs, splitting it automatically.
  • For every argument x in the split output, forbacktickx runs loop... as a child process, with variable=x added to its environment.
  • forbacktickx then exits 0.

Options

  • -p : parallel mode. Do not wait for a loop... instance to finish before spawning the next one. forbacktickx will still wait for all instances of loop to terminate before exiting, though.
  • -o okcodes : okcodes must be a comma-separated list of exit codes. If the -p flag hasn't been given and loop exits with one of the codes in okcodes, forbacktickx will run the following instances of the loop, but if the exit code is not listed in okcodes, forbacktickx will exit immediately with an approximation of the same exit code.
  • -x breakcodes : like the previous option, but with inverted meaning - the listed exit codes are codes that will make forbacktickx break the loop and exit, and the unlisted exit codes will make it keep looping.
  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of spawning loop..., spawn importas -ui variable variable loop.... This substitutes variable into the command line instead of putting it into the environment.

Other options are similar (in name and functionality) to the switches passed to control a substitution mechanism, on purpose; however, forbacktickx does not call the substitution mechanism and has its own semantics for those options.

  • -N : store the whole line in variable, including the terminating newline (or other delimiter).
  • -n : chomp a terminating delimiter from the line from stdin before storing it into variable. This is the default.
  • -C : crunch. If there is an empty line (i.e. that only contains a delimiter), do not call loop. If this option is given, and chomping is active, and the last line of stdin is not terminated by a delimiter, then this last line will not be processed.
  • -c : do not crunch, call loop even if the line is empty. This is the default.
  • -0 : accept null characters on its stdin, using them as delimiters. If this option and a -d option are used simultaneously, the rightmost one wins.
  • -d delim : use the characters in string delim as delimiters for a line. Default is "\n", meaning the input is only split on newlines.

Notes

  • You can start loop... with "importas -u variable variable" to perform variable substitution.
  • forbacktickx is now implemented as a wrapper around the pipeline and forstdin commands, with calls to fdmove to ensure that loop... is called with the proper standard input.
execline-2.9.4.0/doc/foreground.html000066400000000000000000000042661452216466500173100ustar00rootroot00000000000000 execline: the foreground command

execline
Software
skarnet.org

The foreground program

foreground executes a sequence of commands.

Interface

In an execlineb script:

     foreground { prog1... } prog2...
  • foreground reads prog1 in a block. It forks and executes it, then waits for it to complete.
  • foreground sets the ? environment variable to the exit code of prog1. If prog1... was killed by a signal, the ? value is 256 plus the signal number.
  • foreground then execs into prog2....

Notes

  • foreground is the basic sequence operator: it takes two commands and executes them one by one. execline scripts require it to wrap external commands that exit instead of natively supporting the "perform some action, then execute some other program" model.
  • foreground prog1... "" prog2... is equivalent to sh -c 'prog1... ; exec prog2...'.
  • 256 and above are not valid exit codes for commands, so when the ? environment variable contains 256 or more, it means that the previous command was killed by a signal. There is no ambiguity here, and ? reports exactly what happened to the previous command; foreground does not exit, so there is no need for exit code approximation.
execline-2.9.4.0/doc/forstdin.html000066400000000000000000000103121452216466500167530ustar00rootroot00000000000000 execline: the forstdin command

execline
Software
skarnet.org

The forstdin program

forstdin uses its input as loop elements to run another program.

Interface

In an execlineb script:

     forstdin [ -E | -e ] [ -p | -o okcodes | -x breakcodes ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] variable loop...
  • forstdin reads its standard input as it becomes available, splitting it on every line automatically.
  • For every argument x in the split output, forstdin runs loop... as a child process, with variable=x added to its environment.
  • forstdin then exits 0 if it has read something on stdin, and 1 if it hasn't read anything.

Options

  • -p : parallel mode. Do not wait for a loop... instance to finish before spawning the next one. forstdin will still wait for all instances of loop to terminate before exiting, though.
  • -o okcodes : okcodes must be a comma-separated list of exit codes. If the -p flag hasn't been given and loop exits with one of the codes in okcodes, forstdin will run the following instances of the loop, but if the exit code is not listed in okcodes, forstdin will exit immediately with an approximation of the same exit code.
  • -x breakcodes : like the previous option, but with inverted meaning - the listed exit codes are codes that will make forstdin break the loop and exit, and the unlisted exit codes will make it keep looping.
  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of spawning loop..., spawn importas -ui variable variable loop.... This substitutes variable into the command line instead of putting it into the environment.

Other options are similar (in name and functionality) to the switches passed to control a substitution mechanism, on purpose; however, forstdin does not call the substitution mechanism and has its own semantics for those options.

  • -N : store the whole line in variable, including the terminating newline (or other delimiter).
  • -n : chomp a terminating delimiter from the line from stdin before storing it into variable. This is the default. Note that if chomping is active, and the last line of stdin is not terminated by a delimiter, then this last line will not be processed.
  • -C : crunch. If there is an empty line (i.e. that only contains a delimiter), do not call loop.
  • -c : do not crunch, call loop even if the line is empty. This is the default.
  • -0 : accept null characters on its stdin, using them as delimiters. If this option and a -d option are used simultaneously, the rightmost one wins.
  • -d delim : use the characters in string delim as delimiters for a line. Default is "\n", meaning the input is only split on newlines.

Notes

  • You can start loop... with importas -u variable variable to perform variable substitution.
execline-2.9.4.0/doc/forx.html000066400000000000000000000057511452216466500161140ustar00rootroot00000000000000 execline: the forx command

execline
Software
skarnet.org

The forx program

forx runs a loop.

Interface

In an execlineb script:

     forx [ -E | -e ] [ -p ] [ -o okcodes | -x breakcodes ] variable { args... } loop...
  • forx reads a block and unquotes it. That block contains a list of args.
  • For each argument x in args..., forx runs loop as a child process, with variable=x added to its environment.
  • forx then exits 0.

Options

  • -o okcodes : okcodes must be a comma-separated list of exit codes. If loop exits with one of the codes in okcodes, forx will run the following instances of the loop, but if the exit code is not listed in okcodes, forx will exit immediately with an approximation of the same exit code.
  • -x breakcodes : like the previous option, but with inverted meaning - the listed exit codes are codes that will make forx break the loop and exit, and the unlisted exit codes will make it keep looping.
  • -p : run in parallel. Do not wait for an instance of loop... to exit before spawning the next one. forx will still wait for all instances of loop to terminate before exiting 0. If the -o option has been given, forx will exit 0 if all of the exit codes are in the values listed in the okcodes list, else it will exit 1. If the -x option has been given, forx will exit 0 if none of the exit codes are in the values listed in the breakcodes list, else it will exit 1.
  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of spawning loop..., spawn importas -ui variable variable loop.... This substitutes variable into the command line instead of putting it into the environment.

Notes

  • You can start loop with "importas -u variable variable" if you want variable substitution.
execline-2.9.4.0/doc/getcwd.html000066400000000000000000000036421452216466500164100ustar00rootroot00000000000000 execline: the getcwd program

execline
Software
skarnet.org

The getcwd program

getcwd stores its current working directory into a given environment variable, then executes a program.

Interface

     getcwd [ -E | -e ] var prog...

getcwd stores a fully resolved absolute path (i.e. without any .. or symbolic link components) to its current working directory into the var variable, then execs into prog with its arguments.

Options

  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of exec'ing into prog..., exec into importas -ui var var prog.... This substitutes var into the command line instead of putting it into the environment.

Notes

  • var must be given without a dollar!
  • var must not contain =.
  • Unlike the pwd POSIX command, getcwd does not depend on the PWD environment variable and will exhibit a consistent behaviour no matter the environment.
execline-2.9.4.0/doc/getpid.html000066400000000000000000000033001452216466500163760ustar00rootroot00000000000000 execline: the getpid program

execline
Software
skarnet.org

The getpid program

getpid stores its process ID in a given environment variable, then executes a program.

Interface

     getpid [ -E | -e ] [ -P | -p ] var prog...

getpid stores its PID in the var variable, then execs into prog with its arguments.

Options

  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of exec'ing into prog..., exec into importas -ui var var prog.... This substitutes var into the command line instead of putting it into the environment.
  • -p : get the pid of the current process. This is the default.
  • -P : use getpid's parent pid instead.

Notes

  • var must be given without a dollar!
  • var must not contain =.
execline-2.9.4.0/doc/grammar.html000066400000000000000000000150501452216466500165550ustar00rootroot00000000000000 execline: language design and grammar

execline
Software
skarnet.org

The execline language design and grammar

execline principles

Here are some basic Unix facts:

Knowing that, and wanting lightweight and efficient scripts, I wondered: "Why should the interpreter stay in memory while the script is executing? Why not parse the script once and for all, put it all into one argv, and just execute into that argv, relying on external commands (which will be called from within the script) to control the execution flow?"

execline was born.

  • execline is the first script language to rely entirely on chain loading. An execline script is a single argv, made of a chain of programs designed to perform their action then exec() into the next one.
  • The execlineb command is a launcher: it reads and parses a text file, converting it to an argv, then executes into that argv. It does nothing more.
  • Straightforward scripts like nice -10 echo blah will be run just as they are, without the shell overhead. Here is what the script could look like:
    #!/command/execlineb -P
    nice -10
    echo blah
    
  • More complex scripts will include calls to other execline commands, which are meant to provide some control over the process state and execution flow from inside an argv.

Grammar of an execline script

An execline script can be parsed as follows:

 <instruction> = <> | external options <arglist> <instruction> | builtin options <arglist> <blocklist> <instruction>
 <arglist> = <> | arg <arglist>
 <blocklist> = <> | <block> <blocklist>
 <block> = { <arglist> } | { <instrlist> }
 <instrlist> = <> | <instruction> <instrlist>

(This grammar is ambivalent, but much simpler to understand than the non-ambivalent ones.)

execline features

execline commands can perform some transformations on their argv, to emulate some aspects of a shell. Here are descriptions of these features:

execline-2.9.4.0/doc/heredoc.html000066400000000000000000000030671452216466500165450ustar00rootroot00000000000000 execline: the heredoc program

execline
Software
skarnet.org

The heredoc program

heredoc runs a command with a certain string fed to a file descriptor.

Interface

     heredoc [ -d ] fd string prog...
  • heredoc execs into prog... with string available on the fd file descriptor.
  • string must not contain a null character.

Options

  • -d : run the process feeding string to fd as a grandchild of heredoc. This is meant to prevent a zombie from hanging around if prog... has read string and fails to wait for its children.

Notes

  • heredoc is meant to be used in place of the shell << construct, which includes here-documents into scripts.
execline-2.9.4.0/doc/homeof.html000066400000000000000000000020301452216466500163760ustar00rootroot00000000000000 execline: the homeof program

execline
Software
skarnet.org

The homeof program

homeof prints the home directory of a user.

Interface

     homeof user

homeof finds the name of user's home directory, writes it on stdout, then exits 0. If an error occurs, it prints nothing on stdout but exits 111 with an explanatory message on stderr.

execline-2.9.4.0/doc/if.html000066400000000000000000000047661452216466500155410ustar00rootroot00000000000000 execline: the if command

execline
Software
skarnet.org

The if program

if performs conditional execution.

Interface

In an execlineb script:

     if [ -X ] [ -n ] [ -t | -x exitcode ] { prog1... } prog2...
  • if reads prog1... in a block. It forks and executes it, then waits for it to complete.
  • If prog1 crashes, if prints an error message then exits 128 plus the number of the signal that killed prog1.
  • If prog1 exits with a non-zero code, if exits with an approximation of that code.
  • Else if execs into prog2.

Options

  • -X : treat a crash of prog1 as a non-zero ("false") exit. This is mostly useful in combination with -n.
  • -n : negate the test. If prog1 exits true, then if will exit 1; else it will exec into prog2.
  • -x exitcode : if if needs to exit, it will exit exitcode instead of whatever else it would have exited.
  • -t : if if needs to exit, it will exit 0. This is equivalent to -x 0.

Notes

  • if will exit if prog1... exits false. To use it in an execline script that must run prog3... no matter the result of the test, use a foreground wrapper:
     foreground { if { prog1... } prog2... } prog3... 
    (in execlineb syntax)
  • if prog1... "" prog2... is equivalent to sh -c 'prog1... && exec prog2...'.
execline-2.9.4.0/doc/ifelse.html000066400000000000000000000035211452216466500163760ustar00rootroot00000000000000 execline: the ifelse command

execline
Software
skarnet.org

The ifelse program

ifelse performs conditional execution, with two branches.

Interface

In an execlineb script:

     ifelse [ -X ] [ -n ] { prog1... } { prog2... } prog3...
  • ifelse reads prog1... in a block. It forks and executes it, then waits for it to complete.
  • If prog1 crashes, ifelse prints an error message and exits 128 plus the number of the signal that killed prog1.
  • If prog1 exits with a return code equal to 0, ifelse execs into prog2.
  • Else ifelse execs into prog3.

Options

  • -n : negate the test.
  • -X : do not die if prog1 crashes; treat a crash as a non-zero ("false") exit.

Notes

  • ifelse prog1... "" prog2... "" prog3... is roughly equivalent to sh -c 'prog1... && exec prog2... || exec prog3...'.
execline-2.9.4.0/doc/ifte.html000066400000000000000000000041371452216466500160620ustar00rootroot00000000000000 execline: the ifte command

execline
Software
skarnet.org

The ifte program

ifte performs a conditional alternative.

Interface

In an execlineb script:

     ifte [ -X ] [ -n ] { progthen... } { progelse... } progif...
  • ifte reads progthen... and progelse... in two consecutive blocks.
  • ifte runs progif... as a child process and waits for it to complete.
  • If progif... crashes (i.e. is killed by a signal), ifte prints an error message, then exits 128 plus the number of the signal that killed progif.
  • If progif... exits zero, ifte execs into progthen..., else it execs into progelse....

Options

  • -X : do not exit if progif crashes; instead, proceed as if the test had returned false.
  • -n : negate the test. progthen... will be run iff progif... exits nonzero.

Notes

ifte is a simpler version of ifthenelse. It performs only conditional execution, not instruction sequence.

"ifthenelse { progif } { progthen } { progelse } remainder" is the equivalent of "foreground { ifte { progthen } { progelse } progif } remainder".

execline-2.9.4.0/doc/ifthenelse.html000066400000000000000000000040061452216466500172540ustar00rootroot00000000000000 execline: the ifthenelse command

execline
Software
skarnet.org

The ifthenelse program

ifthenelse performs a conditional alternative.

Interface

In an execlineb script:

     ifthenelse [ -X ] [ -s ] { progif... } { progthen... } { progelse... } prog...
  • ifthenelse reads progif..., progthen... and progelse... in 3 consecutive blocks.
  • ifthenelse runs progif... as a child process and waits for it to complete.
  • If progif... crashes (i.e. is killed by a signal), ifthenelse prints an error message, then exits 128 plus the number of the signal that killed progif.
  • If progif... exits zero, ifthenelse runs progthen... as a child process, else it runs progelse....
  • ifthenelse waits for its child to complete and puts the exit status in the ? environment variable. It then execs into prog....

Options

  • -X : if progif crashes, do not exit; proceed as if it had returned false.
  • -s : magic scoping hack. This option does powerful but ugly things, and is left undocumented on purpose.
execline-2.9.4.0/doc/importas.html000066400000000000000000000055721452216466500167750ustar00rootroot00000000000000 execline: the importas program

execline
Software
skarnet.org

The importas program

importas replaces a literal with the value of an environment variable, then executes another program.

Interface

     importas [ -i | -D default ] [ -u ] [ -s ] [ -C | -c ] [ -N | -n ] [ -d delim ] variable envvar prog...
  • importas fetches the value of envvar in the environment. If neither the -D nor the -i option is given, and envvar is undefined, no word is returned (that is different from the empty word).
  • importas then performs variable substitution on prog..., with variable as key and that string as value.
  • importas then execs into the modified prog....

Options

  • -D default : If this option is given and envvar is undefined, substitute default for the value of variable instead of no word. For instance, to substitute the empty word, use -D "".
  • -i : Insist. If envvar is undefined, importas will not do anything; instead, it will exit 100 with an error message. This has precedence over any -D option.
  • -u : Unexport. envvar will be removed from the environment after the substitution. importas -u variable envvar is equivalent to importas variable envvar unexport envvar.
  • Other options are used to control the substitution mechanism.

Notes

  • When envvar is undefined, and the -D option is not given, any variable substitution with variable as the key will return no word; that is true even when the ${variable} form to be substituted happens in the middle of a word (with a prefix and/or a postfix), which means the whole word will be deleted. If this is not the behaviour you want, use the -D option.
execline-2.9.4.0/doc/index.html000066400000000000000000000212521452216466500162370ustar00rootroot00000000000000 execline: a small scripting language

Software
skarnet.org

execline

What is it?

execline is a (non-interactive) scripting language, like sh - but its syntax is quite different from a traditional shell syntax. The execlineb program is meant to be used as an interpreter for a text file; the other commands are essentially useful inside an execlineb script.

execline is as powerful as a shell: it features conditional loops, getopt-style option handling, filename globbing, and more. Meanwhile, its syntax is far more logical and predictable than the shell's syntax, and has no security issues.


Installation

Requirements

  • A POSIX-compliant system with a standard C development environment
  • GNU make, version 3.81 or later.
  • skalibs version 2.14.0.0 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.

The following optional dependencies are also supported:

  • If you're using musl and want nsswitch-like functionality: nsss version 0.2.0.4 or later (build-time and boot-time)

Licensing

execline is free software. It is available under the ISC license.

Download

  • The current released version of execline is 2.9.4.0.
  • Alternatively, you can checkout a copy of the execline git repository:
     git clone git://git.skarnet.org/execline 
  • There's also a GitHub mirror of the execline git repository.

Compilation

  • See the enclosed INSTALL file for installation details.
  • Starting with 2.9.2.0, there's an --enable-multicall configure option to save disk space.

Upgrade notes

  • This page lists the differences to be aware of between the previous versions of execline and the current one.

Reference

Commands

All these commands exit 111 if they encounter a temporary error, and 100 if they encounter a permanent error - such as a misuse. They exit 127 if they're trying to execute into a program and cannot find it, and 126 if they fail to execute into a program for another reason.

(Script parser / launcher)

(Process state control)

(Basic block management)

(Variable management)

(Loops)

(Positional parameters and options management)

(Miscellaneous)

(Multicall configuration)

Provided scripts: example .profile replacement

Fun stuff

Related resources

execline manual pages

execline discussion

  • execline is discussed on the skaware mailing-list.
execline-2.9.4.0/doc/loopwhilex.html000066400000000000000000000045251452216466500173260ustar00rootroot00000000000000 execline: the loopwhilex command

execline
Software
skarnet.org

The loopwhilex program

loopwhilex performs a conditional loop.

Interface

     loopwhilex [ -n ] [ -o okcodes | -x breakcodes ] prog...
  • loopwhilex runs prog... as a child process and waits for it to complete.
  • As long as prog exits zero, loopwhile runs it again.
  • loopwhilex then exits with an approximation of the last prog invocation's exit code.

Options

  • -o okcodes : okcodes must be a comma-separated list of exit codes. loopwhilex will keep looping as long as prog exits with one of the codes in okcodes.
  • -x breakcodes : like the previous option, but with inverted meaning - the listed exit codes are codes that will break the loop and exit, and the unlisted exit codes will keep the loop running.
  • -n : negate the test. This option is now redundant, and may disappear soon.

Notes

  • loopwhilex prog... is equivalent to loopwhilex -n -x 0 prog... and loopwhilex -o 0 prog...
  • Be careful: execline maintains no state, in particular it uses no real variables, and environment will be of no use here since every instance of prog... runs as a separate child process. To avoid being stuck in an infinite loop, prog... should modify some external state - for instance, the filesystem.
execline-2.9.4.0/doc/multidefine.html000066400000000000000000000055271452216466500174440ustar00rootroot00000000000000 execline: the multidefine command

execline
Software
skarnet.org

The multidefine program

multidefine splits a value and defines several variables at once, then executes another program.

Interface

In an execlineb script:

     multidefine [ -0 ] [ -r ] [ -C | -c ] [ -N | -n ] [ -d delim ] value { variables... } prog...
  • multidefine reads a block containing a list of variables. That block must not be empty.
  • multidefine splits value, and performs other operations depending on the given options.
  • multidefine performs parallel substitution on prog..., using all of the variables in the block as keys. The first word in the split value is assigned to the first variable, the second word is assigned to the second variable, and so on. Every variable is substituted with exactly one word.
  • If a variable is the empty word, then the word in the split value corresponding to its position is not substituted. So you can use empty words to pad the list of variables and only perform substition on the relevant fields.
  • multidefine then execs into the modified prog....

Options

  • -0 : if there are more variables in the block than there are words in the split value, the excess variables will be replaced with zero word. Without this option, the excess variables are replaced with the empty word.
  • -r : behave similarly to the "read" shell command. If there are more words in the split value than there are variables in the block, the last variable will be replaced with all the remaining words (and will be split). Without this option, the last variable is replaced with a single word, and the excess words are lost.
  • Other options are used to control the substitution mechanism. Note that the value is always split.
execline-2.9.4.0/doc/multisubstitute.html000066400000000000000000000065401452216466500204210ustar00rootroot00000000000000 execline: the multisubstitute command

execline
Software
skarnet.org

The multisubstitute program

multisubstitute performs several substitutions at once in its argv, then executes another program.

Interface

In an execlineb script:

     multisubstitute
     {
       [ define [ -N | -n ] [ -s ] [ -C | -c ] [ -d delim ] variable value ]
       [ importas [ -i | -D default ] [ -N | -n ] [ -s ] [ -C | -c ] [ -d delim ] variable envvar ]
       [ elglob [ -v ] [ -w ] [ -s ] [ -m ] [ -e ] [ -0 ] variable pattern ]
       [ elgetpositionals [ -P sharp ] ]
       [ multidefine value { variable... } ]
       ...
     }
     prog...
  • multisubstitute reads a block containing a series of substitution commands. It performs all those substitutions on prog... in parallel. Check the relevant documentation page to learn about the syntax of each substitution command.
  • multisubstitute then execs into the modified prog....

Options

  • If an importas directive was given with the -i option, and the looked up variable is undefined, multisubstitute will exit 100.

Rationale

Security

multisubstitute can be used to avoid unwanted serial substitutions. Consider the following script:

 #!/command/execlineb
 export A wrong
 define B ${A}
 importas A A
 echo ${B}

Running it will print wrong, because A is substituted after B. On the contrary, the following script:

 #!/command/execlineb
 export A wrong
 multisubstitute
 {
   define B ${A}
   importas A A
 }
 echo ${B}

will print ${A}, because A and B are substituted at the same time. Serial substitution may be what you want - but when in doubt, always perform parallel substitution.

Efficiency

Substitution is a costly mechanism: the whole argv is read three times and rewritten twice. Serial substitution multiplies the cost by the number of substitutions, whereas parallel substitution pays the price only once.

Credits

Paul Jarc first originated the idea of the multisubstitute command and a possible syntax.

execline-2.9.4.0/doc/pipeline.html000066400000000000000000000040721452216466500167360ustar00rootroot00000000000000 execline: the pipeline command

execline
Software
skarnet.org

The pipeline program

pipeline runs two commands with a pipe between them.

Interface

In an execlineb script:

     pipeline [ -d ] [ -r | -w ] { prog1... } prog2...
  • pipeline reads prog1... in a block and unquotes it.
  • It runs prog1... as a child process and execs into prog2..., with a pipe between prog1's stdout and prog2's stdin.
  • prog1's pid is available in prog2 as the ! environment variable.

Options

  • -d : run prog1... as a grandchild of pipeline. This is meant to prevent a zombie from hanging around if prog2... fails to wait for its children.
  • -r : make prog1... the writer and prog2... the reader. This is the default.
  • -w : make prog1... the reader and prog2... the writer.

Notes

  • You can easily create a chain of pipes: execlineb -Pc 'pipeline { a } pipeline { b } c' is roughly equivalent to sh -c 'exec a | b | c', except that shells usually run c as a child process like a and b, and exec has no effect.
execline-2.9.4.0/doc/piperw.html000066400000000000000000000020511452216466500164320ustar00rootroot00000000000000 execline: the piperw command

execline
Software
skarnet.org

The piperw program

piperw creates a pipe (an anonymous one), then executes a program.

Interface

     piperw fdr fdw prog...

piperw creates a pipe with descriptor fdw as the writing end and descriptor fdr as the reading end. It then execs into prog with its arguments.

execline-2.9.4.0/doc/posix-cd.html000066400000000000000000000047161452216466500166640ustar00rootroot00000000000000 execline: the posix-cd command

execline
Software
skarnet.org

The posix-cd program

posix-cd changes the current working directory to a given directory, then executes a program.

Interface

     posix-cd [ -L | -P ] dir prog...

posix-cd changes the current working directory to dir according to the POSIX specification for a cd external utility. Then, if prog... is not empty, it execs into it.

Notes

  • When execline has been configured with the --enable-pedantic-posix option, the cd command is a symbolic link to it. So scripts calling cd will use posix-cd. When this configuration option has not been given, cd is a symbolic link to execline-cd.
  • posix-cd fully conforms to the POSIX specification. When prog... is not empty, the behaviour of a cd utility is not specified by POSIX, so posix-cd extends the spec to be actually useful and usable in an execline program with the same interface as the regular execline cd command.
  • Nobody ever executes or needs the external version (i.e. not a shell builtin) of the POSIX cd command. Compared to execline's regular cd binary, execline-cd, posix-cd is uselessly bloated and slow. The only reason it exists is that some distributions refuse to package execline correctly unless it is strictly POSIX-compliant; the --enable-pedantic-posix configure option is there to satisfy their requirements.
execline-2.9.4.0/doc/posix-umask.html000066400000000000000000000053651452216466500174170ustar00rootroot00000000000000 execline: the posix-umask command

execline
Software
skarnet.org

The posix-umask program

posix-umask changes its file mode creation mask, then executes a program.

Interface

     posix-umask [ -S ] [ mask ] [ prog... ]

When called with no argument, posix-umask prints the value of the file mode creation mask of the invoking process, then exits 0.

When called with a mask argument, posix-umask changes its file mode creation mask; then, if prog... is not empty, it execs into it.

posix-umask interprets mask as specified by the POSIX specification for a umask external utility.

Notes

  • When execline has been configured with the --enable-pedantic-posix option, the umask command is a symbolic link to it. So scripts calling umask will use posix-umask. When this configuration option has not been given, umask is a symbolic link to execline-umask.
  • posix-umask fully conforms to the POSIX specification. When prog... is not empty, the behaviour of a umask utility is not specified by POSIX, so posix-umask extends the spec to be actually useful and usable in an execline program with the same interface as the regular execline umask command.
  • Nobody ever executes or needs the external version (i.e. not a shell builtin) of the POSIX umask command. Compared to execline's regular umask binary, execline-umask, posix-umask is uselessly bloated and slow. The only reason it exists is that some distributions refuse to package execline correctly unless it is strictly POSIX-compliant; the --enable-pedantic-posix configure option is there to satisfy their requirements.
execline-2.9.4.0/doc/quine-dam.txt000066400000000000000000000102051452216466500166570ustar00rootroot00000000000000#! /command/execlineb -P # Public Domain. # See comments below. # (Search for "HERE".) # define -sCd "\n" lns " ${p} ${bubble} is the end of the quine's data. ${p} They represent the following code, with various quotations: ${p} ${b} (backslash) is represented as ${d}${ob}b${cb} ${p} ${q} (double quote) is represented as ${d}${ob}q${cb} ${p} ${p} (sharp/pound/shibboleth/whatever) is represented as ${d}${ob}p${cb} ${p} ${ob} (open brace) is represented as ${d}${ob}ob${cb} ${p} ${cb} (closed brace) is represented as ${d}${ob}cb${cb} ${p} ${d} (dollar) is represented as ${d}${ob}d${cb} ${p} ${bubble} (the magic word) is represented as ${d}${ob}bubble${cb} ${p} (The point of the magic word is to allow the reader ${p} to conveniently skip over the large data section.) ${p} ${p} Now we have the quine's code! ${p} ${p} First, print the lines that come before the data. foreground ${ob} printf %s ${b}${p}${b}!${q} ${q} ${cb} foreground ${ob} printf %s${b}${b}n ${q}/command/execlineb -P${q} ${cb} foreground ${ob} printf %s${b}${b}n ${b}${p}${q} Public Domain.${q} ${cb} foreground ${ob} printf %s${b}${b}n ${b}${p}${q} See comments below.${q} ${cb} foreground ${ob} printf %s ${b}${p}${q} (Search for ${q} ${cb} foreground ${ob} printf %s${b}${b}n ${b}${q}${bubble}${b}${q}.) ${cb} foreground ${ob} printf %s${b}${b}n ${b}${p} ${cb} foreground ${ob} printf %s ${q}define -sCd ${b}${q}${b}${b}n${b}${q} lns ${b}${q}${q} ${cb} ${p} Next, print the data themselves, as data. foreground ${ob} forx -E lin ${ob} ${d}${ob}lns${cb} ${cb} multisubstitute ${ob} define b ${d}${ob}b${cb} define q ${d}${ob}q${cb} define p ${d}${ob}p${cb} define ob ${d}${ob}ob${cb} define cb ${d}${ob}cb${cb} define d ${d}${ob}d${cb} define bubble ${d}${ob}bubble${cb} define intron ${d}${ob}intron${cb} ${cb} printf ${b}${b}n%s ${d}${ob}lin${cb} ${cb} foreground ${ob} printf %s${b}${b}n ${b}${q} ${cb} ${p} Finally, use the data to print the code! forx -E lin ${ob} ${d}${ob}lns${cb} ${cb} multisubstitute ${ob} define b ${b}${b} define q ${b}${q} define p ${b}${p} define ob ${b}${ob} define cb ${b}${cb} define d ${d} define bubble ${bubble} define intron ${q}${intron}${q} ${cb} printf %s${b}${b}n ${d}${ob}lin${cb} ${p} That's all, folks! - Well, that wasn't so hard, was it? ${p} (This quine was written by - see ${p} ${p} for more information on quines and how to write them.)" # HERE is the end of the quine's data. # They represent the following code, with various quotations: # \ (backslash) is represented as ${b} # " (double quote) is represented as ${q} # # (sharp/pound/shibboleth/whatever) is represented as ${p} # { (open brace) is represented as ${ob} # } (closed brace) is represented as ${cb} # $ (dollar) is represented as ${d} # HERE (the magic word) is represented as ${bubble} # (The point of the magic word is to allow the reader # to conveniently skip over the large data section.) # # Now we have the quine's code! # # First, print the lines that come before the data. foreground { printf %s \#\!" " } foreground { printf %s\\n "/command/execlineb -P" } foreground { printf %s\\n \#" Public Domain." } foreground { printf %s\\n \#" See comments below." } foreground { printf %s \#" (Search for " } foreground { printf %s\\n \"HERE\".) } foreground { printf %s\\n \# } foreground { printf %s "define -sCd \"\\n\" lns \"" } # Next, print the data themselves, as data. foreground { forx -E lin { ${lns} } multisubstitute { define b ${b} define q ${q} define p ${p} define ob ${ob} define cb ${cb} define d ${d} define bubble ${bubble} define intron ${intron} } printf \\n%s ${lin} } foreground { printf %s\\n \" } # Finally, use the data to print the code! forx -E lin { ${lns} } multisubstitute { define b \\ define q \" define p \# define ob \{ define cb \} define d $ define bubble HERE define intron "NOTICE HOW THIS SENTENCE APPEARS ONLY ONCE IN THIS QUINE?" } printf %s\\n ${lin} # That's all, folks! - Well, that wasn't so hard, was it? # (This quine was written by - see # # for more information on quines and how to write them.) execline-2.9.4.0/doc/quine-jriou.txt000066400000000000000000000022441452216466500172520ustar00rootroot00000000000000#!/command/execlineb define A "#!/command/execlineb" define B "fine G $ foreground { echo ${C} } echo -n foreground ${D} define C ${E}${C}${R}foreground ${D} echo ${G}${D}A${H} ${H}${R}foreground ${D} echo define A ${G}${D}C${H}${G}${D}A${H}${G}${D}C${H} ${H}${R}echo -n define B ${G}${D}C${H} ${H}${R}foreground ${D} echo -n ${G}${D}B${H} ${H}${R}foreground ${D} multisubstitute ${D} define C ${E}${C} define D ${E}${D}${R}define E ${E}${E}${R}define H ${E}${H} define R ${C}${R}${C} ${H} de } echo ${B}" foreground { define C \" foreground { echo ${A} } foreground { echo define A ${C}${A}${C} } echo -n define B ${C} } foreground { echo -n ${B} } foreground { multisubstitute { define C \" define D \{ define E \\ define H \} define R " " } define G $ foreground { echo ${C} } echo -n foreground ${D} define C ${E}${C}${R}foreground ${D} echo ${G}${D}A${H} ${H}${R}foreground ${D} echo define A ${G}${D}C${H}${G}${D}A${H}${G}${D}C${H} ${H}${R}echo -n define B ${G}${D}C${H} ${H}${R}foreground ${D} echo -n ${G}${D}B${H} ${H}${R}foreground ${D} multisubstitute ${D} define C ${E}${C} define D ${E}${D}${R}define E ${E}${E}${R}define H ${E}${H} define R ${C}${R}${C} ${H} de } echo ${B} execline-2.9.4.0/doc/quine-prj-2.txt000066400000000000000000000003271452216466500170540ustar00rootroot00000000000000#!/command/execlineb define e "#!/command/execlineb define e ${q}${E}${q} multisubstitute { define q ${b}${q} define b ${b}${b} define E $e } echo $e" multisubstitute { define q \" define b \\ define E $e } echo $e execline-2.9.4.0/doc/quine-prj-3.txt000066400000000000000000000003171452216466500170540ustar00rootroot00000000000000#!/command/execlineb -P define e "#!/command/execlineb -P define e ${q}${E}${q} export E $e define q ${b}${q} define b ${b}${b} importas E E echo $e" export E $e define q \" define b \\ importas E E echo $e execline-2.9.4.0/doc/quine-prj.txt000066400000000000000000000003011452216466500167050ustar00rootroot00000000000000#!/command/execlineb define e "#!/command/execlineb define e $q${E}${q} env e=$e define q ${b}${q} define b ${b}${b} importas E e echo $e" env e=$e define q \" define b \\ importas E e echo $e execline-2.9.4.0/doc/redirfd.html000066400000000000000000000071151452216466500165510ustar00rootroot00000000000000 execline: the redirfd command

execline
Software
skarnet.org

The redirfd program

redirfd redirects a given file descriptor to a file, then executes a program.

Interface

     redirfd [ -r | -w | -u | -a | -x ] [ -n ] [ -b ] fd file prog...

redirfd redirects the file descriptor number fd to file, then execs into prog....

Options

One and only one of the -r, -w, -u, -a, or -x options must be given; the -n and -b options may be added in any case.

  • -r : open file for reading.
  • -w : open file for writing, truncating it if it already exists.
  • -u : open file for reading and writing.
  • -a : open file for appending, creating it if it doesn't exist.
  • -x : open file for writing, creating it, failing if it already exists.
  • -n : open file in non-blocking mode.
  • -b : change mode of file after opening it: to non-blocking mode if the -n option was not given, to blocking mode if it was.

Notes

  • redirfd -r n file prog... is roughly equivalent to sh -c 'exec prog... n<file'
  • redirfd -w n file prog... is roughly equivalent to sh -c 'exec prog... n>file'
  • redirfd -u n file prog... is roughly equivalent to sh -c 'exec prog... n<>file'
  • redirfd -a n file prog... is roughly equivalent to sh -c 'exec prog... n>>file'
  • redirfd -x n file prog... has no portable shell equivalent.

Special fifo handling

The -n and -b options are especially useful with named pipes.

  • Opening a fifo for reading, blocking if there is no writer: redirfd -r n fifo prog...
  • Opening a fifo for reading, with instant success even if there is no writer, and blocking at the first attempt to read from it: redirfd -r -nb n fifo prog...
  • Opening a fifo for writing, blocking if there is no reader: redirfd -w n fifo prog...
  • Opening a fifo for writing, with instant success even if there is no reader: redirfd -w -nb n fifo prog.... Warning: the first attempt to write to the fifo will raise a SIGPIPE if there is still no reader at that time. The named pipe semantics normally do not allow a fifo to be open for writing without a reading end, and you should know what you are doing if you're using redirfd this way.
execline-2.9.4.0/doc/runblock.html000066400000000000000000000053501452216466500167500ustar00rootroot00000000000000 execline: the runblock program

execline
Software
www.skarnet.org

The runblock program

runblock's purpose is to help you write execline commands in the execline language. It can only be used inside an execline script. If the script has been given blocks as arguments, runblock allows you to execute one of the blocks individually. It also allows you to give those blocks as a set of arguments to another command.

Interface

     runblock [ -P ] [ -n argshift ] [ -r ] n cmd...
  • runblock skips the first argshift positional parameters. It does that to allow you to design commands that take simple arguments and blocks.
  • Then runblock looks for and parses blocks in the positional parameters.
  • If the -r option is present: runblock skips n blocks and execs into the remaining arguments.
  • Else it skips n-1 blocks and execs into the nth one.
  • If cmd... is not empty, then instead of directly executing the block or the remainder, runblock appends the selected set of arguments to the cmd... command line.
  • Normally runblock pops its environment frame before executing. If the -P option has been given, it does not pop.
  • Of course, if the block structure doesn't match, runblock exits 100 with an error message.

Example: implementing the ifelse command

Suppose that we want to implement the ifelse command as an execline script, using the ifte command. runblock allows us to do it in a simple way:

 #!/command/execlineb
 ifte { runblock 2 } { runblock -r 2 } runblock 1

That's it.

Credits

The runblock idea, as well as the ifelse idea, comes from Paul Jarc.

execline-2.9.4.0/doc/shift.html000066400000000000000000000046251452216466500162520ustar00rootroot00000000000000 execline: the shift program

execline
Software
www.skarnet.org

The shift program

shift shifts the positional parameters of an execline script.

Interface

     shift [ -n argn ] [ -b blockn ] prog...
  • shift shifts argn positional parameters, then blockn blocks. It then execs prog....
  • By default, argn and blockn are both zero; but if neither the -n nor the -b option is given, then argn is 1 and blockn is 0.

Details

  • shift reads the number of "positional parameters" in the # environment variable. Let n be that number.
  • If the # environment variable is not set or does not contain a valid number, or one of the 0, 1, ..., n environment variables is not set, shift exits 100 with an error message.
  • shift calculates a shift value m, corresponding to argn arguments followed by enough arguments to make blockn blocks.
  • It shifts the positional parameters m times: the value of the m+1 variable becomes the value of the 1 variable, m+2 becomes 2 and so on, and # is set to n-m (floored at zero).
  • shift then execs into prog....

Notes

  • shift is a standard shell builtin. Be careful if you want to use it outside of an execline script.
  • The -b option is only useful to implement execline commands in the execline language. You shouldn't normally have to use it.
execline-2.9.4.0/doc/trap.html000066400000000000000000000077311452216466500161040ustar00rootroot00000000000000 execline: the trap command

execline
Software
skarnet.org

The trap program

trap traps signals and runs a variety of commands according to the signals it catches.

Interface

In an execlineb script:

     trap [ -x ]
     {
       [ SIGTERM { progsigterm... } ]
       [ quit { progsigquit... } ]
       [ 1 { progsighup... } ]
       [ default { progdefault... } ]
       ...
     }
     prog...
  • trap reads a sequence of directives in a block. It expects at least one directive.
  • Each directive is a keyword followed by a block.
  • The keyword can be the special word default, a signal name (case-insensitive, with or without the SIG prefix), or a signal number. The block following it is a command line to run when the specified event occurs.
  • trap sets traps for the various directives it reads. A trap for SIGTERM will be triggered when the trap program receives a SIGTERM. A default trap will be used for any signal that is not caught by another trap.
  • It spawns a child executing prog....
  • It sets the ! environment variable to the pid of the prog... process, and the SIGNAL environment variable to the trapped signal.
  • Whenever it catches a signal, it spawns the program described in the corresponding directive. It will not spawn a program for the same signal twice: if the first subprocess is still active when another instance of the same signal arrives, this second instance is ignored.
  • When prog... exits, trap exits with an approximation of the same exit code.

Options

  • -x : forward signals. If this option is given, any signal that trap receives and that is not explicitly trapped will be sent to prog. By default, trap does not forward any signals, and does not ignore them either - for instance a SIGTERM, unless caught by a SIGTERM directive, will kill the trap process (and leave prog running). With the -x option, without a SIGTERM directive, a SIGTERM will still be caught by trap, that will send it to prog. Note that if a default directive is present, this option does nothing.

Notes

  • Programs defined in command line directives can start with importas ! ! to retrieve the pid of prog in $!. If they need the signal number, which can be the case in default directives, they can for instance use multisubstitute { importas ! ! importas SIGNAL SIGNAL } to get both $! and $SIGNAL substitutions.
  • The -x option is basically a shortcut for a default { multisubstitute { importas ! ! importas SIGNAL SIGNAL } kill -$SIGNAL $! } directive.
  • trap is a standard shell builtin, with similar functionality. It is more idiomatic, and probably more efficient, to use that builtin in shell scripts, and to only use the trap program in execline scripts.
execline-2.9.4.0/doc/tryexec.html000066400000000000000000000036241452216466500166160ustar00rootroot00000000000000 execline: the tryexec command

execline
Software
skarnet.org

The tryexec program

tryexec executes into a command line, with a fallback.

Interface

In an execlineb script:

     tryexec [ -n ] [ -c ] [ -l ] [ -a argv0 ] { prog1... } prog2...
  • tryexec reads prog1... in a block. It then executes into it, completely forgetting prog2...
  • If for some reason the execve() fails - for instance, a non-executable prog1 - then tryexec executes into prog2... instead.

Options

  • -n : reverse prog1... and prog2...'s role. The latter becomes the main execution path and the former becomes the fallback.

The -c, -l and -a options have the same semantics as with the exec program.

Notes

  • tryexec prog1... "" prog2... would be equivalent to sh -c 'exec prog1... || exec prog2...', if such a shell construct existed. Unfortunately, the shell language does not offer that functionality.
execline-2.9.4.0/doc/unexport.html000066400000000000000000000022721452216466500170150ustar00rootroot00000000000000 execline: the unexport command

execline
Software
skarnet.org

The unexport program

unexport removes a variable from the environment, then executes a program.

Interface

     unexport var prog...

unexport removes the var variable from the environment, then execs into prog with its arguments.

Notes

  • Unsetting var is quite different from setting it to an empty value. Shell scripts usually won't make the distinction; execline does.
execline-2.9.4.0/doc/upgrade.html000066400000000000000000000266401452216466500165650ustar00rootroot00000000000000 execline: how to upgrade

execline
Software
skarnet.org

What has changed in execline

in 2.9.4.0

  • skalibs dependency bumped to 2.14.0.0.
  • nsss optional dependency bumped to 0.2.0.4.

in 2.9.3.0

in 2.9.2.1

  • No functional changes.

in 2.9.2.0

  • skalibs dependency bumped to 2.13.1.0.
  • New experimental multicall feature, with a new execline binary.

in 2.9.1.0

  • skalibs dependency bumped to 2.13.0.0.
  • nsss optional dependency bumped to 0.2.0.2.
  • New program: eltest.

in 2.9.0.1

  • No functional changes.

in 2.9.0.0

  • skalibs dependency bumped to 2.12.0.0.
  • New options to wait: -o to wait for one of the listed processes, and -a to get the default behaviour.
  • wait now exits 99 on timeout.

in 2.8.3.0

  • skalibs dependency bumped to 2.11.2.0.
  • New options to getpid: -P to get the parent's pid, and -p to get the default behaviour.

in 2.8.2.0

  • skalibs dependency bumped to 2.11.1.0.
  • nsss optional dependency bumped to 0.2.0.1.
  • New options to case.

in 2.8.1.0

  • skalibs dependency bumped to 2.11.0.0.
  • New binary: case.

in 2.8.0.1

  • skalibs dependency bumped to 2.10.0.3.

in 2.8.0.0

  • skalibs dependency bumped to 2.10.0.2.
  • backtick options have changed slightly, and now propagates subprocess failure by default.

in 2.7.0.1

  • skalibs dependency bumped to 2.10.0.1.

in 2.7.0.0

  • skalibs dependency bumped to 2.10.0.0.
  • nsss optional dependency bumped to 0.1.0.0.
  • forstdin now exits 1 on immediate EOF, and only splits on newlines by default.
  • forbacktickx, which is a wrapper around forstdin, gets the same changes.
  • Input-processing binaries (not substitution binaries!) now chomp by default.
  • New -N option to deactivate chomping.
  • New default directive to trap, replacing the timeout one, which was ill-suited to that program.

in 2.6.1.1

  • skalibs dependency bumped to 2.9.3.0.

in 2.6.1.0

  • The envfile format has changed. It is now more expressive and largely compatible with systemd's EnvironmentFile format. The new format is a superset of the old one, so old envfiles should still be understood by the new binary.

in 2.6.0.2

  • No functional changes

in 2.6.0.1

  • skalibs dependency bumped to 2.9.2.1.

in 2.6.0.0

  • skalibs dependency bumped to 2.9.2.0.
  • dollarat now has its -0 and -d priority unified. (Rightmost priority.)
  • runblock now accepts a command line prefix, given as runblock's own command line.
  • New binary: posix-umask.
  • cd has been renamed execline-cd.
  • umask has been renamed execline-umask.
  • At installation time, cd and umask symbolic links are created, pointing to either the posix- or execline- -prefixed version of the commands, depending on whether the --enable-pedantic-posix option was given or not.

in 2.5.3.0

  • skalibs dependency bumped to 2.9.1.0.
  • --enable-pedantic-posix configure option added.
  • posix-cd binary added.
  • wait binary made POSIX-compliant.

in 2.5.2.0

  • skalibs dependency bumped to 2.9.0.0.

in 2.5.1.0

  • skalibs dependency bumped to 2.8.0.0.
  • New command: envfile.
  • Everything now builds as PIC by default no matter the toolchain's settings. Use the --disable-all-pic configure option to build executables and static libraries as non-PIC.

in 2.5.0.1

  • skalibs dependency bumped to 2.7.0.0
  • Optional nsss support added.

in 2.5.0.0

  • skalibs dependency bumped to 2.6.4.0
  • The import command has been removed.

in 2.3.0.4

  • skalibs dependency bumped to 2.6.2.0

in 2.3.0.3

  • skalibs dependency bumped to 2.6.0.1

in 2.3.0.2

  • skalibs dependency bumped to 2.6.0.0
  • Commands now exit 127 (not found) or 126 (other error) if they cannot exec into a program they're supposed to.
  • The import command will likely disappear very soon. Please switch to importas as soon as possible!

in 2.3.0.1

  • skalibs dependency bumped to 2.5.1.0

in 2.3.0.0

  • skalibs dependency bumped to 2.5.0.0
  • import is now marked as obsolescent. It is recommanded to use the importas command instead.

in 2.2.0.0

in 2.1.5.0

  • skalibs dependency bumped to 2.3.10.0

in 2.1.4.5

  • skalibs dependency bumped to 2.3.8.3

in 2.1.4.4

  • No functional changes

in 2.1.4.3

  • No functional changes

in 2.1.4.2

  • GNU make dependency pushed back to 3.81
  • skalibs dependency bumped to 2.3.8.0

in 2.1.4.1

  • skalibs dependency bumped to 2.3.7.1

in 2.1.4.0

  • New EXECLINE_BLOCK_END_STRING and EXECLINE_BLOCK_QUOTE_STRING macros
  • New command: withstdinas. It's a simplification of backtick, which is now implemented as a combination of pipeline and withstdinas.
  • Other new command: getcwd.

in 2.1.3.1

  • skalibs dependency bumped to 2.3.6.1

in 2.1.3.0

  • skalibs dependency bumped to 2.3.6.0
  • New configure option: --shebangdir for script creation automation.

in 2.1.2.2

  • skalibs dependency bumped to 2.3.5.1

in 2.1.2.1

  • Bugfix release, no changes

in 2.1.2.0

  • skalibs dependency bumped to 2.3.4.0
  • new command: trap

in 2.1.1.1

  • skalibs dependency bumped to 2.3.3.0
  • execlineb parser made into a library function, for easier inclusion in other programs

in 2.1.1.0

in 2.1.0.0

  • skalibs dependency bumped to 2.3.1.0
  • foreground now sets the ? environment variable to 256 plus the signal number when its block was killed by a signal (in previous releases it used 126).
  • New rules for exit codes of forx, loopwhilex, forbacktickx
  • New -e option to loopwhilex, deprecating the -x option.

in 2.0.2.1

  • skalibs dependency bumped to 2.3.0.0

in 2.0.2.0

  • skalibs dependency bumped to 2.2.1.0
  • New command: fdswap
  • New -D option to backtick

in 2.0.1.1

  • skalibs dependency bumped to 2.2.0.0
  • Parallel build fix

in 2.0.1.0

  • skalibs dependency bumped to 2.1.0.0
  • -u option added to import and importas

in 2.0.0.0

  • The build system has completely changed. It is now a standard ./configure && make && sudo make install build system. See the enclosed INSTALL file for details.
  • slashpackage is not activated by default.
  • shared libraries are neither built nor used by default.
  • skalibs dependency bumped to 2.0.0.0
  • The obsolete -E option to backtick, forx and forbacktickx is not supported anymore.
  • multisubstitute does not support the "backtick" directive anymore.
execline-2.9.4.0/doc/wait.html000066400000000000000000000063451452216466500161020ustar00rootroot00000000000000 execline: the wait command

execline
Software
skarnet.org

The wait program

wait waits for a set of children, then executes a program.

Interface

In an execlineb script:

     wait [ -I | -i ] [ -a | -o ] [ -r | -t timeout ] { [ pids... ] } prog...
  • wait reads a list of pids in a (possibly empty) block, and unquotes it.
  • wait waits for every child whose pid is listed in pids.... If pids... is an empty list, it waits for every child process it has.
  • wait then execs into prog....

Options

  • -r : equivalent to -t 0. Do not pause: only reap processes that are already dead when wait is invoked.
  • -t timeout : wait for a maximum of timeout milliseconds. If there still are living processes among pids... (or among wait's children if pids... is an empty list), after timeout milliseconds, they will not be reaped.
  • -I : loose. If wait times out while waiting for children to die, it will still exec into prog.... This is the default.
  • -i : strict. If wait times out, it will print an error message and exit 99.
  • -o : wait for one of the listed pids — exec into prog as soon as one of the listed children dies. (If no pid is listed, wait for one child to die.) The ! environment variable will be set to the pid that died, and the ? environment variable will contain an approximation of its exit code. If no listed child has died before wait has to exec (either because it timed out or it has no suitable children left), the ? and ! environment variables are unset.
  • -a : wait for all of the listed pids. Do not touch the ! or ? variables. This is the default.

Notes

  • For POSIX compatibility, wait also works when it cannot find a block. In that case, all the options are still supported and have the same effect, but the rest of the command line is interpreted as pids... arguments and wait does not execute into a program; instead, it exits with a conforming exit code.
execline-2.9.4.0/doc/withstdinas.html000066400000000000000000000051571452216466500174770ustar00rootroot00000000000000 execline: the withstdinas command

execline
Software
skarnet.org

The withstdinas program

withstdinas reads the entirety of its standard input in an environment variable, and runs another program with that additional environment variable.

Interface

In an execlineb script:

     withstdinas [ -i | -I | -D default ] [ -N | -n ] [ -E | -e ] variable prog...
  • withstdinas reads its stdin until EOF.
  • It then execs into prog..., with variable added to the environment; the value of variable is what was read on stdin.

Options

  • -N : do not chomp an ending newline off stdin.
  • -n : chomp an ending newline off stdin. This is the default.
  • -e : no autoimport. This is the default.
  • -E : autoimport. Instead of exec'ing into prog..., exec into importas -ui variable variable prog.... This substitutes variable into the command line instead of putting it into the environment.

The other options tell withstdinas what to do if its input is not suitable as the contents of an environment variable, i.e. it contains a null character:

  • -i : withstdinas exits 1.
  • -I : variable is removed from the environment, and execution proceeds.
  • -D default : the value of variable is set to default, and execution proceeds.
  • neither of those options: the value of variable is set to whatever the start of the input is, up to the first null character; and execution proceeds.

Notes

  • You can start prog... with "importas -u variable variable" to perform variable substitution.
execline-2.9.4.0/examples/000077500000000000000000000000001452216466500153115ustar00rootroot00000000000000execline-2.9.4.0/examples/etc/000077500000000000000000000000001452216466500160645ustar00rootroot00000000000000execline-2.9.4.0/examples/etc/env-startup/000077500000000000000000000000001452216466500203545ustar00rootroot00000000000000execline-2.9.4.0/examples/etc/env-startup/EDITOR000066400000000000000000000000031452216466500212560ustar00rootroot00000000000000vi execline-2.9.4.0/examples/etc/env-startup/GZIP000066400000000000000000000000041452216466500210420ustar00rootroot00000000000000-r9 execline-2.9.4.0/examples/etc/env-startup/LESS000066400000000000000000000000221452216466500210370ustar00rootroot00000000000000-fMqrIX -b16 -z-2 execline-2.9.4.0/examples/etc/env-startup/LESSCHARSET000066400000000000000000000000051452216466500220520ustar00rootroot00000000000000utf8 execline-2.9.4.0/examples/etc/env-startup/MAIL000066400000000000000000000000001452216466500210070ustar00rootroot00000000000000execline-2.9.4.0/examples/etc/env-startup/PAGER000066400000000000000000000000051452216466500211300ustar00rootroot00000000000000less execline-2.9.4.0/examples/etc/env-startup/PATH000066400000000000000000000000351452216466500210310ustar00rootroot00000000000000/usr/local/bin:/usr/bin:/bin execline-2.9.4.0/examples/etc/env-startup/SHELL000066400000000000000000000000241452216466500211420ustar00rootroot00000000000000/etc/execline-shell execline-2.9.4.0/examples/etc/execline-shell000077500000000000000000000005541452216466500207170ustar00rootroot00000000000000#!/bin/execlineb -S0 backtick -n defaulthome { if -nt { backtick -n defaultuser { id -un } importas -u defaultuser defaultuser importas -D $defaultuser USER USER redirfd -w 2 /dev/null homeof ${USER} } s6-echo / } importas -u defaulthome defaulthome importas -D $defaulthome HOME HOME tryexec { ${HOME}/.execline-shell $@ } /bin/sh $@ execline-2.9.4.0/examples/etc/execline-startup000077500000000000000000000004271452216466500213110ustar00rootroot00000000000000#!/bin/execlineb -S0 /bin/multisubstitute { importas -i HOME HOME importas -i LOGNAME LOGNAME } /bin/export USER ${LOGNAME} /bin/s6-envdir /etc/env-startup /bin/fdblock 0 /bin/fdblock 1 /bin/fdblock 2 /bin/tryexec { ${HOME}/.execline-loginshell $@ } /etc/execline-shell $@ execline-2.9.4.0/package/000077500000000000000000000000001452216466500150665ustar00rootroot00000000000000execline-2.9.4.0/package/deps-build000066400000000000000000000000631452216466500170400ustar00rootroot00000000000000/package/prog/skalibs /package/admin/nsss $usensss execline-2.9.4.0/package/deps.mak000066400000000000000000000352211452216466500165160ustar00rootroot00000000000000# # This file has been generated by tools/gen-deps.sh # src/execline/background.o src/execline/background.lo: src/execline/background.c src/include/execline/execline.h src/execline/backtick.o src/execline/backtick.lo: src/execline/backtick.c src/include/execline/execline.h src/execline/case.o src/execline/case.lo: src/execline/case.c src/include/execline/execline.h src/execline/define.o src/execline/define.lo: src/execline/define.c src/include-local/exlsn.h src/execline/dollarat.o src/execline/dollarat.lo: src/execline/dollarat.c src/execline/elgetopt.o src/execline/elgetopt.lo: src/execline/elgetopt.c src/include/execline/execline.h src/execline/elgetpositionals.o src/execline/elgetpositionals.lo: src/execline/elgetpositionals.c src/include-local/exlsn.h src/execline/elglob.o src/execline/elglob.lo: src/execline/elglob.c src/include-local/exlsn.h src/execline/eltest.o src/execline/eltest.lo: src/execline/eltest.c src/execline/emptyenv.o src/execline/emptyenv.lo: src/execline/emptyenv.c src/include/execline/execline.h src/execline/envfile.o src/execline/envfile.lo: src/execline/envfile.c src/execline/exec.o src/execline/exec.lo: src/execline/exec.c src/execline/execline-cd.o src/execline/execline-cd.lo: src/execline/execline-cd.c src/execline/execline-umask.o src/execline/execline-umask.lo: src/execline/execline-umask.c src/execline/execlineb.o src/execline/execlineb.lo: src/execline/execlineb.c src/include/execline/execline.h src/include-local/exlsn.h src/execline/exit.o src/execline/exit.lo: src/execline/exit.c src/execline/export.o src/execline/export.lo: src/execline/export.c src/execline/fdblock.o src/execline/fdblock.lo: src/execline/fdblock.c src/execline/fdclose.o src/execline/fdclose.lo: src/execline/fdclose.c src/execline/fdmove.o src/execline/fdmove.lo: src/execline/fdmove.c src/execline/fdreserve.o src/execline/fdreserve.lo: src/execline/fdreserve.c src/execline/fdswap.o src/execline/fdswap.lo: src/execline/fdswap.c src/execline/forbacktickx.o src/execline/forbacktickx.lo: src/execline/forbacktickx.c src/include/execline/config.h src/include/execline/execline.h src/execline/foreground.o src/execline/foreground.lo: src/execline/foreground.c src/include/execline/execline.h src/execline/forstdin.o src/execline/forstdin.lo: src/execline/forstdin.c src/include/execline/execline.h src/execline/forx.o src/execline/forx.lo: src/execline/forx.c src/include/execline/config.h src/include/execline/execline.h src/execline/getcwd.o src/execline/getcwd.lo: src/execline/getcwd.c src/include/execline/execline.h src/execline/getpid.o src/execline/getpid.lo: src/execline/getpid.c src/include/execline/execline.h src/execline/heredoc.o src/execline/heredoc.lo: src/execline/heredoc.c src/execline/homeof.o src/execline/homeof.lo: src/execline/homeof.c src/execline/if.o src/execline/if.lo: src/execline/if.c src/include/execline/execline.h src/execline/ifelse.o src/execline/ifelse.lo: src/execline/ifelse.c src/include/execline/execline.h src/execline/ifte.o src/execline/ifte.lo: src/execline/ifte.c src/include/execline/execline.h src/execline/ifthenelse.o src/execline/ifthenelse.lo: src/execline/ifthenelse.c src/include/execline/execline.h src/execline/importas.o src/execline/importas.lo: src/execline/importas.c src/include-local/exlsn.h src/execline/loopwhilex.o src/execline/loopwhilex.lo: src/execline/loopwhilex.c src/include/execline/execline.h src/execline/multidefine.o src/execline/multidefine.lo: src/execline/multidefine.c src/include-local/exlsn.h src/execline/multisubstitute.o src/execline/multisubstitute.lo: src/execline/multisubstitute.c src/include/execline/execline.h src/include-local/exlsn.h src/execline/pipeline.o src/execline/pipeline.lo: src/execline/pipeline.c src/include/execline/execline.h src/execline/piperw.o src/execline/piperw.lo: src/execline/piperw.c src/execline/posix-cd.o src/execline/posix-cd.lo: src/execline/posix-cd.c src/execline/posix-umask.o src/execline/posix-umask.lo: src/execline/posix-umask.c src/execline/redirfd.o src/execline/redirfd.lo: src/execline/redirfd.c src/execline/runblock.o src/execline/runblock.lo: src/execline/runblock.c src/include/execline/execline.h src/execline/shift.o src/execline/shift.lo: src/execline/shift.c src/include/execline/execline.h src/execline/trap.o src/execline/trap.lo: src/execline/trap.c src/include/execline/execline.h src/execline/tryexec.o src/execline/tryexec.lo: src/execline/tryexec.c src/include/execline/execline.h src/execline/unexport.o src/execline/unexport.lo: src/execline/unexport.c src/execline/wait.o src/execline/wait.lo: src/execline/wait.c src/include/execline/config.h src/include/execline/execline.h src/execline/withstdinas.o src/execline/withstdinas.lo: src/execline/withstdinas.c src/include/execline/execline.h src/libexecline/el_execsequence.o src/libexecline/el_execsequence.lo: src/libexecline/el_execsequence.c src/include/execline/execline.h src/libexecline/el_getstrict.o src/libexecline/el_getstrict.lo: src/libexecline/el_getstrict.c src/include/execline/execline.h src/libexecline/el_gspawn0.o src/libexecline/el_gspawn0.lo: src/libexecline/el_gspawn0.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_exec.lo: src/libexecline/el_modif_and_exec.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_modif_and_spawn.o src/libexecline/el_modif_and_spawn.lo: src/libexecline/el_modif_and_spawn.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_parse.o src/libexecline/el_parse.lo: src/libexecline/el_parse.c src/include/execline/execline.h src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_buffer.lo: src/libexecline/el_parse_from_buffer.c src/include/execline/execline.h src/libexecline/el_parse_from_string.o src/libexecline/el_parse_from_string.lo: src/libexecline/el_parse_from_string.c src/include/execline/execline.h src/libexecline/el_popenv.o src/libexecline/el_popenv.lo: src/libexecline/el_popenv.c src/include/execline/execline.h src/libexecline/el_pushenv.o src/libexecline/el_pushenv.lo: src/libexecline/el_pushenv.c src/include/execline/execline.h src/libexecline/el_semicolon.o src/libexecline/el_semicolon.lo: src/libexecline/el_semicolon.c src/include/execline/execline.h src/libexecline/el_spawn0.o src/libexecline/el_spawn0.lo: src/libexecline/el_spawn0.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_substandrun.o src/libexecline/el_substandrun.lo: src/libexecline/el_substandrun.c src/include-local/exlsn.h src/libexecline/el_substandrun_str.o src/libexecline/el_substandrun_str.lo: src/libexecline/el_substandrun_str.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/el_substitute.o src/libexecline/el_substitute.lo: src/libexecline/el_substitute.c src/include/execline/execline.h src/libexecline/el_transform.o src/libexecline/el_transform.lo: src/libexecline/el_transform.c src/include/execline/execline.h src/libexecline/el_vardupl.o src/libexecline/el_vardupl.lo: src/libexecline/el_vardupl.c src/include/execline/execline.h src/libexecline/exlp.o src/libexecline/exlp.lo: src/libexecline/exlp.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_define.o src/libexecline/exlsn_define.lo: src/libexecline/exlsn_define.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_elglob.o src/libexecline/exlsn_elglob.lo: src/libexecline/exlsn_elglob.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_exlp.o src/libexecline/exlsn_exlp.lo: src/libexecline/exlsn_exlp.c src/include-local/exlsn.h src/libexecline/exlsn_free.o src/libexecline/exlsn_free.lo: src/libexecline/exlsn_free.c src/include-local/exlsn.h src/libexecline/exlsn_importas.o src/libexecline/exlsn_importas.lo: src/libexecline/exlsn_importas.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_main.o src/libexecline/exlsn_main.lo: src/libexecline/exlsn_main.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_multidefine.lo: src/libexecline/exlsn_multidefine.c src/include/execline/execline.h src/include-local/exlsn.h background: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} background: src/execline/background.o ${LIBEXECLINE} backtick: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} backtick: src/execline/backtick.o ${LIBEXECLINE} case: EXTRA_LIBS := -lskarnet case: src/execline/case.o ${LIBEXECLINE} define: EXTRA_LIBS := -lskarnet define: src/execline/define.o ${LIBEXECLINE} dollarat: EXTRA_LIBS := -lskarnet dollarat: src/execline/dollarat.o elgetopt: EXTRA_LIBS := -lskarnet elgetopt: src/execline/elgetopt.o ${LIBEXECLINE} elgetpositionals: EXTRA_LIBS := -lskarnet elgetpositionals: src/execline/elgetpositionals.o ${LIBEXECLINE} elglob: EXTRA_LIBS := -lskarnet elglob: src/execline/elglob.o ${LIBEXECLINE} eltest: EXTRA_LIBS := -lskarnet eltest: src/execline/eltest.o emptyenv: EXTRA_LIBS := -lskarnet emptyenv: src/execline/emptyenv.o ${LIBEXECLINE} envfile: EXTRA_LIBS := -lskarnet envfile: src/execline/envfile.o exec: EXTRA_LIBS := -lskarnet exec: src/execline/exec.o execline-cd: EXTRA_LIBS := -lskarnet execline-cd: src/execline/execline-cd.o execline-umask: EXTRA_LIBS := -lskarnet execline-umask: src/execline/execline-umask.o execlineb: EXTRA_LIBS := -lskarnet execlineb: src/execline/execlineb.o ${LIBEXECLINE} exit: EXTRA_LIBS := -lskarnet exit: src/execline/exit.o export: EXTRA_LIBS := -lskarnet export: src/execline/export.o fdblock: EXTRA_LIBS := -lskarnet fdblock: src/execline/fdblock.o fdclose: EXTRA_LIBS := -lskarnet fdclose: src/execline/fdclose.o fdmove: EXTRA_LIBS := -lskarnet fdmove: src/execline/fdmove.o fdreserve: EXTRA_LIBS := -lskarnet fdreserve: src/execline/fdreserve.o fdswap: EXTRA_LIBS := -lskarnet fdswap: src/execline/fdswap.o forbacktickx: EXTRA_LIBS := -lskarnet forbacktickx: src/execline/forbacktickx.o foreground: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} foreground: src/execline/foreground.o ${LIBEXECLINE} forstdin: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} forstdin: src/execline/forstdin.o ${LIBEXECLINE} forx: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} forx: src/execline/forx.o ${LIBEXECLINE} getcwd: EXTRA_LIBS := -lskarnet getcwd: src/execline/getcwd.o ${LIBEXECLINE} getpid: EXTRA_LIBS := -lskarnet getpid: src/execline/getpid.o ${LIBEXECLINE} heredoc: EXTRA_LIBS := -lskarnet heredoc: src/execline/heredoc.o homeof: EXTRA_LIBS := -lskarnet ${MAYBEPTHREAD_LIB} homeof: src/execline/homeof.o ${LIBNSSS} if: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} if: src/execline/if.o ${LIBEXECLINE} ifelse: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} ifelse: src/execline/ifelse.o ${LIBEXECLINE} ifte: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} ifte: src/execline/ifte.o ${LIBEXECLINE} ifthenelse: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} ifthenelse: src/execline/ifthenelse.o ${LIBEXECLINE} importas: EXTRA_LIBS := -lskarnet importas: src/execline/importas.o ${LIBEXECLINE} loopwhilex: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} loopwhilex: src/execline/loopwhilex.o ${LIBEXECLINE} multidefine: EXTRA_LIBS := -lskarnet multidefine: src/execline/multidefine.o ${LIBEXECLINE} multisubstitute: EXTRA_LIBS := -lskarnet multisubstitute: src/execline/multisubstitute.o ${LIBEXECLINE} pipeline: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} pipeline: src/execline/pipeline.o ${LIBEXECLINE} piperw: EXTRA_LIBS := -lskarnet piperw: src/execline/piperw.o posix-cd: EXTRA_LIBS := -lskarnet posix-cd: src/execline/posix-cd.o posix-umask: EXTRA_LIBS := -lskarnet posix-umask: src/execline/posix-umask.o redirfd: EXTRA_LIBS := -lskarnet redirfd: src/execline/redirfd.o runblock: EXTRA_LIBS := -lskarnet runblock: src/execline/runblock.o ${LIBEXECLINE} shift: EXTRA_LIBS := -lskarnet shift: src/execline/shift.o ${LIBEXECLINE} trap: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} trap: src/execline/trap.o ${LIBEXECLINE} tryexec: EXTRA_LIBS := -lskarnet tryexec: src/execline/tryexec.o ${LIBEXECLINE} unexport: EXTRA_LIBS := -lskarnet unexport: src/execline/unexport.o wait: EXTRA_LIBS := -lskarnet wait: src/execline/wait.o ${LIBEXECLINE} withstdinas: EXTRA_LIBS := -lskarnet withstdinas: src/execline/withstdinas.o ${LIBEXECLINE} ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) libexecline.a.xyzzy: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_spawn.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_gspawn0.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_importas.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o else libexecline.a.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo endif libexecline.so.xyzzy: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo execline: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} ${MAYBEPTHREAD_LIB} execline: src/multicall/execline.o ${LIBEXECLINE} ${LIBNSSS} INTERNAL_LIBS := execline-2.9.4.0/package/info000066400000000000000000000001141452216466500157400ustar00rootroot00000000000000package=execline version=2.9.4.0 category=admin package_macro_name=EXECLINE execline-2.9.4.0/package/modes000066400000000000000000000014041452216466500161170ustar00rootroot00000000000000background 0755 backtick 0755 case 0755 define 0755 dollarat 0755 elgetopt 0755 elgetpositionals 0755 elglob 0755 eltest 0755 execline-cd 0755 execline-umask 0755 emptyenv 0755 envfile 0755 exec 0755 exit 0755 execlineb 0755 export 0755 fdblock 0755 fdclose 0755 fdreserve 0755 fdmove 0755 fdswap 0755 forbacktickx 0755 foreground 0755 forstdin 0755 forx 0755 getcwd 0755 getpid 0755 heredoc 0755 homeof 0755 if 0755 ifelse 0755 ifte 0755 ifthenelse 0755 importas 0755 loopwhilex 0755 multidefine 0755 multisubstitute 0755 piperw 0755 pipeline 0755 posix-cd 0755 posix-umask 0755 redirfd 0755 runblock 0755 shift 0755 trap 0755 tryexec 0755 unexport 0755 wait 0755 withstdinas 0755 execline 0755 execline-2.9.4.0/package/targets.mak000066400000000000000000000021511452216466500172300ustar00rootroot00000000000000LIBEXEC_TARGETS := LIB_DEFS := EXECLINE=execline ifeq ($(MULTICALL),1) BIN_TARGETS := execline CONTENTS := $(notdir $(wildcard src/execline/deps-exe/*)) BIN_SYMLINKS := cd umask $(CONTENTS) EXTRA_TARGETS += src/multicall/execline.c define symlink_definition SYMLINK_TARGET_$(1) := execline endef $(foreach name,$(BIN_SYMLINKS),$(eval $(call symlink_definition,$(name)))) src/multicall/execline.c: tools/gen-multicall.sh $(CONTENTS:%=src/$(package)/%.c) ./tools/gen-multicall.sh > src/multicall/execline.c src/multicall/execline.o: src/multicall/execline.c src/include/execline/config.h src/include/execline/execline.h else BIN_TARGETS := $(notdir $(wildcard src/execline/deps-exe/*)) BIN_SYMLINKS := cd umask ifeq ($(PEDANTIC_POSIX),1) SYMLINK_TARGET_cd := posix-cd SYMLINK_TARGET_umask := posix-umask else SYMLINK_TARGET_cd := execline-cd SYMLINK_TARGET_umask := execline-umask endif $(DESTDIR)$(bindir)/define: ./define 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 $@ ; } endif execline-2.9.4.0/patch-for-solaris000077500000000000000000000007511452216466500167610ustar00rootroot00000000000000#!/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 execline-2.9.4.0/src/000077500000000000000000000000001452216466500142625ustar00rootroot00000000000000execline-2.9.4.0/src/execline/000077500000000000000000000000001452216466500160565ustar00rootroot00000000000000execline-2.9.4.0/src/execline/background.c000066400000000000000000000023241452216466500203420ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #define USAGE "background [ -d ] { command... }" int main (int argc, char const **argv, char const *const *envp) { pid_t pid ; int argc1 ; int df = 0 ; size_t i = 2 ; char fmt[PID_FMT + 2] = "!=" ; PROG = "background" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "d", &l) ; if (opt == -1) break ; switch (opt) { case 'd' : df = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } argc1 = el_semicolon(argv) ; if (!argc1) strerr_dief1x(100, "empty block") ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (argc1 + 1 == argc) df = 0 ; argv[argc1] = 0 ; pid = df ? gcspawn(argv[0], argv, envp, 0, 0, 0) : cspawn(argv[0], argv, envp, 0, 0, 0) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; if (argc1 + 1 == argc) return 0 ; i += pid_fmt(fmt+i, pid) ; fmt[i++] = 0 ; xmexec_en(argv + argc1 + 1, envp, fmt, i, 1) ; } execline-2.9.4.0/src/execline/backtick.c000066400000000000000000000051371452216466500200030ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #define USAGE "backtick [ -i | -I | -x | -D default ] [ -N | -n ] [ -E | -e ] var { prog... } remainder..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const **argv, char const *const *envp) { subgetopt localopt = SUBGETOPT_ZERO ; int argc1, fdwstat ; stralloc value = STRALLOC_ZERO ; char const *var ; char const *val ; int insist = 2, chomp = 1, doimport = 0 ; char const *def = 0 ; PROG = "backtick" ; for (;;) { int opt = subgetopt_r(argc, argv, "iINnxD:Ee", &localopt) ; if (opt < 0) break ; switch (opt) { case 'i' : insist = 2 ; break ; case 'I' : insist = 0 ; break ; case 'N' : chomp = 0 ; break ; case 'n' : chomp = 1 ; break ; case 'x' : insist = 1 ; def = 0 ; break ; case 'D' : insist = 1 ; def = localopt.arg ; break ; case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= localopt.ind ; argv += localopt.ind ; if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; argc-- ; var = *argv++ ; argc1 = el_semicolon(argv) ; if (!argc1) strerr_dief1x(100, "empty block") ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; argv[argc1] = 0 ; { pid_t pid = child_spawn1_pipe(argv[0], argv, envp, &fdwstat, 1) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; if (!slurp(&value, fdwstat) || !stralloc_0(&value)) strerr_diefu1sys(111, "slurp") ; close(fdwstat) ; if (wait_pid(pid, &fdwstat) < 0) strerr_diefu1sys(111, "wait_pid") ; } val = value.s ; if (wait_status(fdwstat)) { if (insist >= 2) strerr_dief1x(wait_estatus(fdwstat), WIFSIGNALED(fdwstat) ? "child process crashed" : "child process exited non-zero") ; else if (insist) val = def ; } else if (strlen(value.s) < value.len - 1) { if (insist >= 2) strerr_dief1x(124, "child process output contained a null character") ; else if (insist) { val = def ; strerr_warnw1x("child process output contained a null character") ; } else value.len = strlen(value.s) + 1 ; } else insist = 0 ; if (!insist && chomp && (value.s[value.len - 2] == '\n')) value.s[--value.len - 1] = 0 ; el_modif_and_exec(argv + argc1 + 1, var, val, doimport) ; } execline-2.9.4.0/src/execline/case.c000066400000000000000000000101441452216466500171350ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #define USAGE "case [ -s | -S ] [ -e | -E ] [ -n | -N ] [ -i ] value { re1 { prog1... } re2 { prog2... } ... } progdefault... " #define dieusage() strerr_dieusage(100, USAGE) static void case_execit (char const *const *argv, char const *expr, char const *s, regmatch_t const *pmatch, size_t n) gccattr_noreturn ; static void case_execit (char const *const *argv, char const *expr, char const *s, regmatch_t const *pmatch, size_t n) { if (n) { size_t exprlen = strlen(expr) ; size_t fmtlen = exprlen + 6 ; for (size_t i = 1 ; i < n ; i++) fmtlen += uint_fmt(0, i) + 2 + pmatch[i].rm_eo - pmatch[i].rm_so ; { size_t m = 0 ; char fmt[fmtlen] ; fmt[m++] = '#' ; fmt[m++] = '=' ; m += uint_fmt(fmt + m, n-1) ; fmt[m++] = 0 ; fmt[m++] = '0' ; fmt[m++] = '=' ; memcpy(fmt + m, expr, exprlen + 1) ; m += exprlen + 1 ; for (size_t i = 1 ; i < n ; i++) { m += uint_fmt(fmt + m, i) ; fmt[m++] = '=' ; memcpy(fmt + m, s + pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so) ; m += pmatch[i].rm_eo - pmatch[i].rm_so ; fmt[m++] = 0 ; } xmexec0_n(argv, fmt, fmtlen, n+1) ; } } else xexec0(argv) ; } int main (int argc, char const **argv, char const *const *envp) { int flagshell = 0 ; int flagextended = 1 ; int flagnosub = 1 ; int flagicase = 0 ; int argc1 ; unsigned int i = 0 ; char const *s ; PROG = "case" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "sSeEnNi", &l) ; if (opt == -1) break ; switch (opt) { case 's' : flagshell = 1 ; break ; case 'S' : flagshell = 0 ; break ; case 'e' : flagextended = 0 ; break ; case 'E' : flagextended = 1 ; break ; case 'N' : flagnosub = 0 ; break ; case 'n' : flagnosub = 1 ; break ; case 'i' : flagicase = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc-- < 2) dieusage() ; s = *argv++ ; argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated case block") ; while (i < argc1) { char const *expr = argv[i++] ; int argc2 ; if (i == argc1) strerr_dief1x(100, "malformed case block") ; argc2 = el_semicolon(argv + i) ; if (i + argc2 >= argc1) strerr_dief1x(100, "unterminated regex block") ; if (flagshell) { int r = fnmatch(expr, s, (flagextended ? 0 : FNM_NOESCAPE) | (flagicase ? FNM_PERIOD : 0) | (flagnosub ? 0 : FNM_PATHNAME)) ; if (!r) { argv[i + argc2] = 0 ; xexec0(argv + i) ; } else if (r != FNM_NOMATCH) strerr_warnw2x("invalid fnmatch pattern: ", expr) ; } else { regex_t re ; { int r ; size_t len = strlen(expr) ; char tmp[len+3] ; tmp[0] = '^' ; memcpy(tmp + 1, expr, len) ; tmp[1+len] = '$' ; tmp[2+len] = 0 ; r = regcomp(&re, tmp, (flagextended ? REG_EXTENDED : 0) | (flagicase ? REG_ICASE : 0) | (flagnosub ? REG_NOSUB : 0) | REG_NEWLINE) ; if (r) { char buf[256] ; regerror(r, &re, buf, 256) ; strerr_diefu4x(r == REG_ESPACE ? 111 : 100, "regcomp \"^", argv[i], "$\": ", buf) ; } } { regmatch_t pmatch[re.re_nsub && !flagnosub ? re.re_nsub + 1 : 1] ; int r = regexec(&re, s, re.re_nsub + 1, pmatch, 0) ; if (!r) { argv[i + argc2] = 0 ; case_execit(argv + i, expr, s, pmatch, flagnosub ? 0 : 1 + re.re_nsub) ; } if (r != REG_NOMATCH) { char buf[256] ; regerror(r, &re, buf, 256) ; strerr_diefu6x(111, "match string \"", s, "\" against regex \"", expr, "\": ", buf) ; } } regfree(&re) ; } i += argc2 + 1 ; } xexec0(argv + argc1 + 1) ; } execline-2.9.4.0/src/execline/define.c000066400000000000000000000004511452216466500174540ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" #define USAGE "define [ -N | -n ] [ -s ] [ -C | -c ] [ -d delim ] key value prog..." int main (int argc, char const **argv, char const *const *envp) { PROG = "define" ; exlsn_main(argc, argv, envp, &exlsn_define, USAGE) ; } execline-2.9.4.0/src/execline/deps-exe/000077500000000000000000000000001452216466500175705ustar00rootroot00000000000000execline-2.9.4.0/src/execline/deps-exe/background000066400000000000000000000000461452216466500216320ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/backtick000066400000000000000000000000461452216466500212660ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/case000066400000000000000000000000311452216466500204200ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/define000066400000000000000000000000311452216466500207370ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/dollarat000066400000000000000000000000121452216466500213060ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/elgetopt000066400000000000000000000000311452216466500213300ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/elgetpositionals000066400000000000000000000000311452216466500230720ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/elglob000066400000000000000000000000311452216466500207510ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/eltest000066400000000000000000000000121452216466500210040ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/emptyenv000066400000000000000000000000311452216466500213540ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/envfile000066400000000000000000000000121452216466500211340ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/exec000066400000000000000000000000121452216466500204300ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/execline-cd000066400000000000000000000000121452216466500216640ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/execline-umask000066400000000000000000000000121452216466500224160ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/execlineb000066400000000000000000000000311452216466500214430ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/exit000066400000000000000000000000121452216466500204550ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/export000066400000000000000000000000121452216466500210250ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/fdblock000066400000000000000000000000121452216466500211100ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/fdclose000066400000000000000000000000121452216466500211230ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/fdmove000066400000000000000000000000121452216466500207640ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/fdreserve000066400000000000000000000000121452216466500214710ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/fdswap000066400000000000000000000000121452216466500207700ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/forbacktickx000066400000000000000000000000121452216466500221560ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/foreground000066400000000000000000000000461452216466500216650ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/forstdin000066400000000000000000000000461452216466500213430ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/forx000066400000000000000000000000461452216466500204710ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/getcwd000066400000000000000000000000311452216466500207620ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/getpid000066400000000000000000000000311452216466500207610ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/heredoc000066400000000000000000000000121452216466500211150ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/homeof000066400000000000000000000000511452216466500207640ustar00rootroot00000000000000${LIBNSSS} -lskarnet ${MAYBEPTHREAD_LIB} execline-2.9.4.0/src/execline/deps-exe/if000066400000000000000000000000461452216466500201110ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/ifelse000066400000000000000000000000461452216466500207620ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/ifte000066400000000000000000000000461452216466500204420ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/ifthenelse000066400000000000000000000000461452216466500216410ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/importas000066400000000000000000000000311452216466500213430ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/loopwhilex000066400000000000000000000000461452216466500217050ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/multidefine000066400000000000000000000000311452216466500220120ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/multisubstitute000066400000000000000000000000311452216466500227730ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/pipeline000066400000000000000000000000461452216466500213200ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/piperw000066400000000000000000000000121452216466500210120ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/posix-cd000066400000000000000000000000121452216466500212320ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/posix-umask000066400000000000000000000000121452216466500217640ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/redirfd000066400000000000000000000000121452216466500211230ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/runblock000066400000000000000000000000311452216466500213240ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/shift000066400000000000000000000000311452216466500206220ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/trap000066400000000000000000000000461452216466500204610ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/execline/deps-exe/tryexec000066400000000000000000000000311452216466500211700ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/unexport000066400000000000000000000000121452216466500213700ustar00rootroot00000000000000-lskarnet execline-2.9.4.0/src/execline/deps-exe/wait000066400000000000000000000000311452216466500204510ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/deps-exe/withstdinas000066400000000000000000000000311452216466500220460ustar00rootroot00000000000000${LIBEXECLINE} -lskarnet execline-2.9.4.0/src/execline/dollarat.c000066400000000000000000000031101452216466500200170ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #define USAGE "dollarat [ -n ] [ -0 | -d delimchar ]" int main (int argc, char const *const *argv) { unsigned int n, i = 0 ; char const *x ; char delim = '\n' ; int zero = 0 ; int nl = 1 ; PROG = "dollarat" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "nd:0", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : nl = 0 ; break ; case 'd' : delim = *l.arg ; zero = 0 ; break ; case '0' : zero = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (zero) delim = 0 ; x = getenv("#") ; if (!x) strerr_dienotset(100, "#") ; if (!uint0_scan(x, &n)) strerr_dieinvalid(100, "#") ; for (; i < n ; i++) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, i+1)] = 0 ; x = getenv(fmt) ; if (!x) strerr_dienotset(100, fmt) ; if (delim || zero) { if ((buffer_puts(buffer_1, x) < 0) || (((i < n-1) || nl) && (buffer_put(buffer_1, &delim, 1) < 0))) strerr_diefu1sys(111, "write to stdout") ; } else { size_t written = 0 ; if (!netstring_put(buffer_1, x, strlen(x), &written)) strerr_diefu1sys(111, "write a netstring to stdout") ; } } if (!buffer_flush(buffer_1)) strerr_diefu1sys(111, "write to stdout") ; return 0 ; } execline-2.9.4.0/src/execline/elgetopt.c000066400000000000000000000042451452216466500200520ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #define USAGE "elgetopt [ -D default ] optstring prog..." int main (int argc, char const *const *argv, char const *const *envp) { size_t envlen = env_len(envp) ; stralloc modif = STRALLOC_ZERO ; char const *x = getenv("#") ; char const *dfl = "1" ; unsigned int n, nbak ; PROG = "elgetopt" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "D:", &l) ; if (opt == -1) break ; switch (opt) { case 'D' : dfl = l.arg ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) strerr_dieusage(100, USAGE) ; if (!x) strerr_dienotset(100, "#") ; if (!uint0_scan(x, &n)) strerr_dieinvalid(100, "#") ; nbak = n++ ; { subgetopt l = SUBGETOPT_ZERO ; char const *args[n+1] ; unsigned int i = 0 ; for ( ; i < n ; i++) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, i)] = 0 ; args[i] = getenv(fmt) ; if (!args[i]) strerr_dienotset(100, fmt) ; } args[n] = 0 ; for (;;) { char hmpf[11] = "ELGETOPT_?" ; int opt = sgetopt_r(n, args, argv[0], &l) ; if (opt == -1) break ; if (opt == '?') return 1 ; hmpf[9] = opt ; if (!env_addmodif(&modif, hmpf, l.arg ? l.arg : dfl)) goto err ; } n -= l.ind ; for (i = 0 ; i < nbak ; i++) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, i+1)] = 0 ; if (!env_addmodif(&modif, fmt, (i < n) ? args[l.ind + i] : 0)) goto err ; } } { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, n)] = 0 ; if (!env_addmodif(&modif, "#", fmt)) goto err ; } { char const *const list[1] = { "ELGETOPT_" } ; char const *v[envlen] ; if (el_pushenv(&satmp, envp, envlen, list, 1) < 0) goto err ; if (!env_make(v, envlen, satmp.s, satmp.len)) goto err ; xmexec_fm(argv+1, v, envlen, modif.s, modif.len) ; } err: strerr_diefu1sys(111, "update environment") ; } execline-2.9.4.0/src/execline/elgetpositionals.c000066400000000000000000000004201452216466500216030ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" #define USAGE "elgetpositionals [ -P num ] prog..." int main (int argc, char const **argv, char const *const *envp) { PROG = "elgetpositionals" ; exlsn_main(argc, argv, envp, &exlsn_exlp, USAGE) ; } execline-2.9.4.0/src/execline/elglob.c000066400000000000000000000004511452216466500174660ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" #define USAGE "elglob [ -v ] [ -w ] [ -s ] [ -m ] [ -e ] [ -0 ] key pattern prog..." int main (int argc, char const **argv, char const *const *envp) { PROG = "elglob" ; exlsn_main(argc, argv, envp, &exlsn_elglob, USAGE) ; } execline-2.9.4.0/src/execline/eltest.c000066400000000000000000000315141452216466500175260ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include enum eltest_opnum_e { T_NOT, T_AND, T_OR, T_LEFTP, T_RIGHTP, T_BLOCK, T_CHAR, T_DIR, T_EXIST, T_REGULAR, T_SGID, T_SYMLINK, T_STICKY, T_NONZERO, T_FIFO, T_READABLE, T_NONZEROFILE, T_TERM, T_SUID, T_WRITABLE, T_EXECUTABLE, T_ZERO, T_EUID, T_EGID, T_SOCKET, T_MODIFIED, T_NEWER, T_OLDER, T_DEVINO, T_STREQUAL, T_STRNEQUAL, T_STRLESSER, T_STRLESSERE, T_STRGREATER, T_STRGREATERE, T_NUMEQUAL, T_NUMNEQUAL, T_NUMGREATER, T_NUMGREATERE, T_NUMLESSER, T_NUMLESSERE, T_ENV, T_MATCH } ; struct eltest_token_s { char const *string ; enum eltest_opnum_e op ; unsigned int type ; } ; struct eltest_node_s { enum eltest_opnum_e op ; unsigned int type ; unsigned int arg1 ; unsigned int arg2 ; char const *data ; } ; static unsigned int eltest_lex (struct eltest_node_s *tree, char const *const *argv) { static struct eltest_token_s const tokens[46] = { { "-n", T_NONZERO, 2 }, { "-z", T_ZERO, 2 }, { "=", T_STREQUAL, 3 }, { "!=", T_STRNEQUAL, 3 }, { "-eq", T_NUMEQUAL, 3 }, { "-ne", T_NUMNEQUAL, 3 }, { "-gt", T_NUMGREATER, 3 }, { "-ge", T_NUMGREATERE, 3 }, { "-lt", T_NUMLESSER, 3 }, { "-le", T_NUMLESSERE, 3 }, { "-f", T_REGULAR, 2 }, { "-h", T_SYMLINK, 2 }, { "-L", T_SYMLINK, 2 }, { "-e", T_EXIST, 2 }, { "-k", T_STICKY, 2 }, { "-a", T_AND, 7 }, { "-o", T_OR, 8 }, { "!", T_NOT, 6 }, { "(", T_LEFTP, 4 }, { ")", T_RIGHTP, 5 }, { "-b", T_BLOCK, 2 }, { "-c", T_CHAR, 2 }, { "-d", T_DIR, 2 }, { "-g", T_SGID, 2 }, { "-p", T_FIFO, 2 }, { "-r", T_READABLE, 2 }, { "-s", T_NONZEROFILE, 2 }, { "-t", T_TERM, 2 }, { "-u", T_SUID, 2 }, { "-w", T_WRITABLE, 2 }, { "-x", T_EXECUTABLE, 2 }, { "-O", T_EUID, 2 }, { "-U", T_EUID, 2 }, { "-G", T_EGID, 2 }, { "-S", T_SOCKET, 2 }, { "-N", T_MODIFIED, 2 }, { "-nt", T_NEWER, 3 }, { "-ot", T_OLDER, 3 }, { "-ef", T_DEVINO, 3 }, { "<", T_STRLESSER, 3 }, { "<=", T_STRLESSERE, 3 }, { ">", T_STRGREATER, 3 }, { ">=", T_STRGREATERE, 3 }, { "-v", T_ENV, 2 }, { "=~", T_MATCH, 3 }, { 0, 0, 0 } } ; unsigned int pos = 0 ; for (; argv[pos] ; pos++) { unsigned int i = 0 ; tree[pos].data = argv[pos] ; for (i = 0 ; tokens[i].string ; i++) if (!strcmp(argv[pos], tokens[i].string)) { tree[pos].op = tokens[i].op ; tree[pos].type = tokens[i].type ; break ; } if (!tokens[i].string) { tree[pos].op = T_NONZERO ; tree[pos].type = 0 ; tree[pos].arg1 = pos ; if (*(argv[pos]) == '\\') tree[pos].data++ ; } } return pos ; } static unsigned int eltest_parse (struct eltest_node_s *tree, unsigned int n) { static char const table[9][13] = { "xssssxsssxxxx", "xxxxxaxxxxxxx", "xsxxsxsssxxxx", "sxxxxxxxxxxxx", "xsxxsxsssxxxx", "nxxxxNxxxAOEs", "xsxxsxsssxxxx", "nxxxxNxxxAsxx", "nxxxxNxxxAOsx" } ; unsigned int stack[n+2] ; unsigned int sp = 0, pos = 0 ; int cont = 1 ; stack[0] = n+1 ; tree[n].type = 5 ; /* add ) for the final reduce */ tree[n+1].type = 1 ; /* add EOF */ while (cont) { switch (table[tree[pos].type][tree[stack[sp]].type]) { case 'x' : /* error */ { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, pos)] = 0 ; strerr_dief2x(100, "parse error at argument ", fmt) ; break ; } case 'a' : /* accept */ { cont = 0 ; break ; } case 's' : /* shift */ { stack[++sp] = pos++ ; break ; } case 'n' : /* reduce -> expr without nots, from atom */ { switch (tree[stack[sp-1]].type) { case 2 : { tree[stack[sp-1]].arg1 = stack[sp] ; sp-- ; break ; } case 3 : { tree[stack[sp-1]].arg1 = stack[sp-2] ; tree[stack[sp-1]].arg2 = stack[sp] ; stack[sp-2] = stack[sp-1] ; sp -= 2 ; break ; } /* default : assert: its a zero */ } tree[stack[sp]].type = 9 ; while (tree[stack[sp-1]].type == 6) { tree[stack[sp-1]].type = 9 ; tree[stack[sp-1]].arg1 = stack[sp] ; sp-- ; } break ; } case 'N' : /* reduce -> expr without nots, from expr */ { if (tree[stack[sp-2]].type != 4) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, pos)] = 0 ; strerr_dief2x(100, "parse error: bad right parenthesis at argument ", fmt) ; } stack[sp-2] = stack[sp-1] ; sp -= 2 ; tree[stack[sp]].type = 9 ; while (tree[stack[sp-1]].type == 6) { tree[stack[sp-1]].type = 9 ; tree[stack[sp-1]].arg1 = stack[sp] ; sp-- ; } break ; } case 'A' : /* reduce -> exprs without ands */ { if (tree[stack[sp-1]].type == 7) { tree[stack[sp-1]].arg1 = stack[sp-2] ; tree[stack[sp-1]].arg2 = stack[sp] ; stack[sp-2] = stack[sp-1] ; sp -= 2 ; } tree[stack[sp]].type = 10 ; break ; } case 'O' : /* reduce -> expr without ors */ { if (tree[stack[sp-1]].type == 8) { tree[stack[sp-1]].arg1 = stack[sp-2] ; tree[stack[sp-1]].arg2 = stack[sp] ; stack[sp-2] = stack[sp-1] ; sp -= 2 ; } tree[stack[sp]].type = 11 ; break ; } case 'E' : /* reduce -> expr */ { tree[stack[sp]].type = 12 ; break ; } default : /* can't happen */ strerr_dief1x(101, "internal error, please submit a bug-report.") ; } } if (sp != 2) strerr_dief1x(100, "parse error: too many left parentheses") ; return stack[1] ; } static int eltest_run (struct eltest_node_s const *tree, unsigned int root) { switch (tree[root].op) { case T_NOT : return !eltest_run(tree, tree[root].arg1) ; case T_AND : return eltest_run(tree, tree[root].arg1) && eltest_run(tree, tree[root].arg2) ; case T_OR : return eltest_run(tree, tree[root].arg1) || eltest_run(tree, tree[root].arg2) ; case T_EXIST : return access(tree[tree[root].arg1].data, F_OK) == 0 ; case T_BLOCK : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISBLK(st.st_mode) ; } case T_CHAR : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISCHR(st.st_mode) ; } case T_DIR : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISDIR(st.st_mode) ; } case T_REGULAR : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISREG(st.st_mode) ; } case T_FIFO : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISFIFO(st.st_mode) ; } case T_SOCKET : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISSOCK(st.st_mode) ; } case T_SYMLINK : { struct stat st ; if (lstat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return S_ISLNK(st.st_mode) ; } case T_SGID : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return (st.st_mode & S_ISGID) ; } case T_SUID : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return (st.st_mode & S_ISUID) ; } case T_STICKY : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return (st.st_mode & S_ISVTX) ; } case T_NONZEROFILE : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return (st.st_size > 0) ; } case T_MODIFIED : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return timespec_cmp(&st.st_mtim, &st.st_atim) > 0 ; } case T_EUID : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return st.st_uid == geteuid() ; } case T_EGID : { struct stat st ; if (stat(tree[tree[root].arg1].data, &st) == -1) return 0 ; return st.st_gid == getegid() ; } case T_READABLE : return access(tree[tree[root].arg1].data, R_OK) == 0 ; case T_WRITABLE : return access(tree[tree[root].arg1].data, W_OK) == 0 ; case T_EXECUTABLE : return access(tree[tree[root].arg1].data, X_OK) == 0 ; case T_NEWER : { struct stat st1, st2 ; if (stat(tree[tree[root].arg1].data, &st1) == -1) return 0 ; if (stat(tree[tree[root].arg2].data, &st2) == -1) return 1 ; return timespec_cmp(&st1.st_mtim, &st2.st_mtim) > 0 ; } case T_OLDER : { struct stat st1, st2 ; if (stat(tree[tree[root].arg1].data, &st1) == -1) return 1 ; if (stat(tree[tree[root].arg2].data, &st2) == -1) return 0 ; return timespec_cmp(&st1.st_mtim, &st2.st_mtim) < 0 ; } case T_DEVINO : { struct stat st1, st2 ; if (stat(tree[tree[root].arg1].data, &st1) == -1) return 0 ; if (stat(tree[tree[root].arg2].data, &st2) == -1) return 1 ; return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino) ; } case T_TERM : { unsigned int fd ; if (!uint0_scan(tree[tree[root].arg1].data, &fd)) strerr_dief2x(100, tree[root].data, " requires an integer argument") ; return isatty(fd) ; } case T_NONZERO : return tree[tree[root].arg1].data[0] ; case T_ZERO : return !tree[tree[root].arg1].data[0] ; case T_STREQUAL : return !strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) ; case T_STRNEQUAL : return !!strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) ; case T_STRLESSER : return strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) < 0 ; case T_STRLESSERE : return strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) <= 0 ; case T_STRGREATER : return strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) > 0 ; case T_STRGREATERE : return strcmp(tree[tree[root].arg1].data, tree[tree[root].arg2].data) >= 0 ; case T_NUMEQUAL : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 == n2 ; } case T_NUMNEQUAL : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 != n2 ; } case T_NUMGREATER : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 > n2 ; } case T_NUMGREATERE : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 >= n2 ; } case T_NUMLESSER : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 < n2 ; } case T_NUMLESSERE : { int n1, n2 ; if (!int_scan(tree[tree[root].arg1].data, &n1) || !int_scan(tree[tree[root].arg2].data, &n2)) goto errorint ; return n1 <= n2 ; } case T_ENV : return !!getenv(tree[tree[root].arg1].data) ; case T_MATCH : { regex_t re ; int r = skalibs_regcomp(&re, tree[tree[root].arg2].data, REG_EXTENDED | REG_NOSUB) ; if (r) { char buf[256] ; regerror(r, &re, buf, 256) ; strerr_diefu4x(r == REG_ESPACE ? 111 : 100, "compile ", tree[tree[root].arg2].data, " into a regular expression: ", buf) ; } r = regexec(&re, tree[tree[root].arg1].data, 0, 0, 0) ; regfree(&re) ; return !r ; } default: strerr_dief1x(101, "operation not implemented") ; } errorint: strerr_dief2x(100, tree[root].data, " requires integer arguments") ; } int main (int argc, char const *const *argv) { struct eltest_node_s tree[argc+2] ; if (argc <= 1) return 1 ; PROG = "eltest" ; return !eltest_run(tree, eltest_parse(tree, eltest_lex(tree, argv+1))) ; } execline-2.9.4.0/src/execline/emptyenv.c000066400000000000000000000047711452216466500201020ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #define USAGE "emptyenv [ -p | -c | -o | -P ] prog..." static void cleanupenv (char const *const *, char const *const *) gccattr_noreturn ; static void cleanupenv (char const *const *argv, char const *const *envp) { stralloc sa = STRALLOC_ZERO ; if (!env_mexec("!", 0) || !env_mexec("?", 0)) goto err ; for (; *envp ; envp++) { char const *s = *envp ; sa.len = 0 ; if (!strncmp(s, "ELGETOPT_", 9) || !strncmp(s, "EXECLINE_", 9) || !strncmp(s, "FD", 2) || (s[0] == '#') || ((s[0] >= '0') && (s[0] <= '9'))) if (!stralloc_catb(&sa, s, str_chr(s, '=')) || !stralloc_0(&sa) || !env_mexec(sa.s, 0)) goto err ; } stralloc_free(&sa) ; xmexec(argv) ; err: strerr_diefu1sys(111, "clean up environment") ; } int main (int argc, char const *const *argv, char const *const *envp) { int flagpath = 0, flagcleanup = 0, flagopt = 0, flagpos = 0 ; PROG = "emptyenv" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "pcoP", &l) ; if (opt == -1) break ; switch (opt) { case 'p' : flagpath = 1 ; break ; case 'c' : flagcleanup = 1 ; break ; case 'o' : flagopt = 1 ; break ; case 'P' : flagpos = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) strerr_dieusage(100, USAGE) ; if (flagcleanup) cleanupenv(argv, envp) ; else if (!flagopt && !flagpos) { char const *newenv[2] = { 0, 0 } ; if (flagpath) for (; *envp ; envp++) if (!strncmp(*envp, "PATH=", 5)) { newenv[0] = *envp ; break ; } xexec_e(argv, newenv) ; } else { static char const *const list[12] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "#", "ELGETOPT_" } ; stralloc sa = STRALLOC_ZERO ; size_t envlen = env_len(envp) ; int n = el_popenv(&sa, envp, envlen, flagpos ? list : list + 11, 11 * flagpos + flagopt) ; if (n < 0) strerr_diefu1sys(111, "pop current execline environment") ; { char const *v[envlen - n + 1] ; if (!env_make(v, envlen-n, sa.s, sa.len)) strerr_diefu1sys(111, "env_make") ; v[envlen-n] = 0 ; xexec_e(argv, v) ; } } } execline-2.9.4.0/src/execline/envfile.c000066400000000000000000000125361452216466500176610ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define USAGE "envfile [ -i | -I ] file prog..." #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "stralloc_catb") static void envfile_scanoct (stralloc *sa, size_t pos) { unsigned int u ; if (!stralloc_0(sa)) dienomem() ; uint_oscan(sa->s + pos, &u) ; sa->s[pos] = u ; sa->len = pos+1 ; } static inline uint8_t envfile_cclass (char c) { switch (c) { case 0 : return 0 ; case '#' : return 1 ; case '\n' : return 2 ; case '=' : return 3 ; case ' ' : case '\t' : case '\f' : case '\r' : return 4 ; case '\\' : return 5 ; case '\"' : return 6 ; case 'a' : case 'b' : case 'f' : return 7 ; case 'n' : case 'r' : case 't' : case 'v' : return 8 ; case '\'' : case '?' : return 9 ; case 'x' : return 10 ; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : return 11 ; case '8' : case '9' : case 'A' : case 'B' : case 'c' : case 'C' : case 'd' : case 'D' : case 'e' : case 'E' : case 'F' : return 12 ; default : return 13 ; } } static inline char envfile_next (char const *file, buffer *b) { char c ; ssize_t r = buffer_get(b, &c, 1) ; if (r < 0) strerr_diefu2sys(111, "read from ", file) ; if (!r) c = 0 ; return c ; } static inline void envfile_parse_config (char const *file, buffer *b, stralloc *sa) { static uint16_t const table[14][14] = { { 0x000e, 0x0001, 0x0020, 0x000f, 0x0000, 0x000f, 0x000f, 0x0012, 0x0012, 0x000f, 0x0012, 0x0012, 0x0012, 0x0012 }, { 0x000e, 0x0001, 0x0020, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 }, { 0x000f, 0x0012, 0x000f, 0x0014, 0x0003, 0x000f, 0x000f, 0x0012, 0x0012, 0x000f, 0x0012, 0x0012, 0x0012, 0x0012 }, { 0x000f, 0x000f, 0x000f, 0x0014, 0x0003, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f }, { 0x004e, 0x0015, 0x0060, 0x0015, 0x0004, 0x0008, 0x0007, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015 }, { 0x004e, 0x0015, 0x0060, 0x0015, 0x0116, 0x0008, 0x0007, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015 }, { 0x00ce, 0x0015, 0x00d0, 0x0015, 0x0016, 0x0008, 0x0007, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015 }, { 0x000f, 0x0017, 0x000f, 0x0017, 0x0017, 0x0009, 0x0005, 0x0017, 0x0017, 0x0017, 0x0017, 0x0017, 0x0017, 0x0017 }, { 0x000f, 0x000f, 0x0025, 0x000f, 0x0015, 0x0015, 0x0015, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f }, { 0x000f, 0x0017, 0x0027, 0x0017, 0x0017, 0x0017, 0x0017, 0x1017, 0x1017, 0x0017, 0x000a, 0x011c, 0x0017, 0x0017 }, { 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x001b, 0x000f, 0x000f, 0x000f, 0x001b, 0x001b, 0x000f }, { 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x0217, 0x000f, 0x000f, 0x000f, 0x0217, 0x0217, 0x000f }, { 0x000f, 0x0417, 0x000f, 0x0417, 0x0417, 0x0409, 0x0405, 0x0417, 0x0417, 0x0417, 0x0417, 0x001d, 0x0417, 0x0417 }, { 0x000f, 0x0417, 0x000f, 0x0417, 0x0417, 0x0409, 0x0405, 0x0417, 0x0417, 0x0417, 0x0417, 0x0817, 0x0417, 0x0417 } } ; unsigned int line = 1 ; size_t mark = 0 ; uint8_t state = 0 ; while (state < 14) { char c = envfile_next(file, b) ; uint16_t what = table[state][envfile_cclass(c)] ; state = what & 0x0f ; if (what & 0x0400) envfile_scanoct(sa, mark) ; if (what & 0x0100) mark = sa->len ; if (what & 0x1000) c = 7 + byte_chr("abtnvfr", 7, c) ; if (what & 0x0010) if (!stralloc_catb(sa, &c, 1)) dienomem() ; if (what & 0x0020) line++ ; if (what & 0x0080) sa->len = mark ; if (what & 0x0040) if (!stralloc_0(sa)) dienomem() ; if (what & 0x0200) { sa->s[sa->len-2] = (fmtscan_num(sa->s[sa->len-2], 16) << 4) + fmtscan_num(sa->s[sa->len-1], 16) ; sa->len-- ; } if (what & 0x0800) envfile_scanoct(sa, mark) ; } if (state > 14) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, line)] = 0 ; strerr_dief4x(1, "in ", file, ": syntax error line ", fmt) ; } } int main (int argc, char const *const *argv) { stralloc modif = STRALLOC_ZERO ; int fd ; char const *name ; int strict = 1 ; PROG = "envfile" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "iI", &l) ; if (opt == -1) break ; switch (opt) { case 'i' : strict = 1 ; break ; case 'I' : strict = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (strcmp(argv[0], "-")) { fd = open_readb(argv[0]) ; name = argv[0] ; } else { fd = 0 ; name = "standard input" ; } if (fd == -1) { if (strict || errno != ENOENT) strerr_diefu2sys(111, "open ", name) ; } else { buffer b ; char buf[BUFFER_INSIZE] ; buffer_init(&b, &buffer_read, fd, buf, BUFFER_INSIZE) ; envfile_parse_config(name, &b, &modif) ; fd_close(fd) ; } xmexec_m(argv + 1, modif.s, modif.len) ; } execline-2.9.4.0/src/execline/envfile.txt000066400000000000000000000030041452216466500202440ustar00rootroot00000000000000envfile parser: class | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 st\ev | \0 # \n = space \ " abf nrtv '? x 0-7 89cde other START | n a a a a a a 0 | END COMMENT START X START X X VAR VAR X VAR VAR VAR VAR COMMENT | n 1 | END COMMENT START COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT VAR | a a a a a a a a 2 | X VAR X EQ WAITEQ X X VAR VAR X VAR VAR VAR VAR WAITEQ | a 3 | X X X EQ WAITEQ X X X X X X X X X EQ | + a + n a a a a a a a a 4 | END VAL START VAL EQ ESC Q VAL VAL VAL VAL VAL VAL VAL VAL | + a + n a m a a a a a a a a 5 | END VAL START VAL SPACE ESC Q VAL VAL VAL VAL VAL VAL VAL SPACE | b + a b + n a a a a a a a a a 6 | END VAL START VAL SPACE ESC Q VAL VAL VAL VAL VAL VAL VAL Q | a a a a a a a a a a 7 | X Q X Q Q QESC VAL Q Q Q Q Q Q Q ESC | n a a a 8 | X X VAL X VAL VAL VAL X X X X X X X QESC | a n a a a a s a s a a m a a a 9 | X Q Q Q Q Q Q Q Q Q HEX0 OCT1 Q Q HEX0 | a a a a | X X X X X X X HEX1 X X X HEX1 HEX1 X HEX1 | a h a h a h b | X X X X X X X Q X X X Q Q X OCT1 | o a o a o a o o o a o a o a o a a o a o a c | X Q X Q Q QESC VAL Q Q Q Q OCT2 Q Q OCT2 | o a o a o a o o o a o a o a o a a O o a o a d | X Q X Q Q QESC VAL Q Q Q Q Q Q Q END = e, X = f 16 states, 9 actions -> 13 bits a 0x0010 add cur n 0x0020 line++ + 0x0040 add \0 (definition complete) b 0x0080 go back to mark m 0x0100 set mark h 0x0200 calc hex o 0x0400 calc oct before a O 0x0800 calc oct after a s 0x1000 turn cur special before a execline-2.9.4.0/src/execline/exec.c000066400000000000000000000021461452216466500171510ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "exec [ -c ] [ -l ] [ -a argv0 ] prog..." int main (int argc, char const **argv, char const *const *envp) { static char const *const zero = 0 ; char const *executable = 0 ; char const *argv0 = 0 ; int dash = 0 ; PROG = "exec" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "cla:", &l) ; if (opt == -1) break ; switch (opt) { case 'c' : envp = &zero ; break ; case 'l' : dash = 1 ; break ; case 'a' : argv0 = l.arg ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) strerr_dieusage(100, USAGE) ; executable = argv[0] ; if (argv0) argv[0] = argv0 ; if (dash) { size_t n = strlen(argv[0]) ; char dashed[n+2] ; dashed[0] = '-' ; memcpy(dashed+1, argv[0], n+1) ; argv[0] = (char const *)dashed ; xexec_ae(executable, argv, envp) ; } else xexec_ae(executable, argv, envp) ; } execline-2.9.4.0/src/execline/execline-cd.c000066400000000000000000000005311452216466500204010ustar00rootroot00000000000000/* ISC license. */ #include #include #include #define USAGE "cd path prog..." int main (int argc, char const *const *argv) { PROG = "execline-cd" ; if (argc < 3) strerr_dieusage(100, USAGE) ; if (chdir(argv[1]) == -1) strerr_diefu2sys(111, "chdir to ", argv[1]) ; xexec(argv+2) ; } execline-2.9.4.0/src/execline/execline-umask.c000066400000000000000000000006151452216466500211360ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "umask value prog..." int main (int argc, char const *const *argv) { unsigned int m ; PROG = "execline-umask" ; if (argc < 3) strerr_dieusage(100, USAGE) ; if (!uint_oscan(argv[1], &m)) strerr_dieusage(100, USAGE) ; umask(m) ; xexec(argv+2) ; } execline-2.9.4.0/src/execline/execlineb.c000066400000000000000000000152101452216466500201570ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "exlsn.h" #define USAGE "execlineb [ -p | -P | -S nmin | -s nmin ] [ -q | -w | -W ] [ -e ] [ -c commandline ] script args" static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, unsigned int nmin, char const *dollar0, int doshift) { exlsn_t info = EXLSN_ZERO ; unsigned int n = argc > nmin ? argc : nmin ; unsigned int i = 0 ; if (!genalloc_ready(elsubst_t, &info.data, 3 + n)) return -1 ; if (!stralloc_ready(&info.vars, 6 + (n << 1))) goto err ; stralloc_catb(&info.vars, "#\0" "0\0@", 6) ; { elsubst_t blah[3] ; char fmt[UINT_FMT] ; blah[0].var = 0 ; blah[0].value = 0 ; blah[0].n = 1 ; if (!stralloc_catb(&info.values, fmt, uint_fmt(fmt, argc)) || !stralloc_0(&info.values)) goto err ; blah[1].var = 2 ; blah[1].value = info.values.len ; blah[1].n = 1 ; if (!stralloc_catb(&info.values, dollar0, strlen(dollar0) + 1)) goto err ; blah[2].var = 4 ; blah[2].value = info.values.len ; blah[2].n = doshift && n == nmin ? 0 : argc ; genalloc_catb(elsubst_t, &info.data, blah, 3) ; } for (; i < n ; i++) { elsubst_t blah = { .var = info.vars.len, .value = info.values.len, .n = 1 } ; char fmt[UINT_FMT] ; if (!stralloc_catb(&info.vars, fmt, uint_fmt(fmt, i+1)) || !stralloc_0(&info.vars)) goto err ; if (!stralloc_catb(&info.values, i < argc ? argv[i] : "", i < argc ? strlen(argv[i]) + 1 : 1)) goto err ; genalloc_append(elsubst_t, &info.data, &blah) ; if (i == nmin && doshift) { elsubst_t *p = genalloc_s(elsubst_t, &info.data) + 2 ; /* hit $@ in-place */ p->value = blah.value ; p->n = argc - nmin ; } } { stralloc dst = STRALLOC_ZERO ; int r = el_substitute(&dst, sa->s, sa->len, info.vars.s, info.values.s, genalloc_s(elsubst_t, &info.data), genalloc_len(elsubst_t, &info.data)) ; if (r < 0) goto err ; exlsn_free(&info) ; stralloc_free(sa) ; *sa = dst ; return r ; } err: exlsn_free(&info) ; return -1 ; } int main (int argc, char const *const *argv, char const *const *envp) { stralloc sa = STRALLOC_ZERO ; stralloc modif = STRALLOC_ZERO ; int nc ; int flagstrict = -1 ; unsigned int nmin = 0 ; char const *stringarg = 0 ; char const *dollar0 = *argv ; unsigned int flagpushenv = 2 ; PROG = "execlineb" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "pPqwWec:S:s:", &l) ; if (opt == -1) break ; switch (opt) { case 'p' : flagpushenv = 1 ; break ; case 'P' : flagpushenv = 0 ; break ; case 'q' : flagstrict = 0 ; break ; case 'w' : flagstrict = 1 ; break ; case 'W' : flagstrict = 2 ; break ; case 'c' : stringarg = l.arg ; break ; case 'e' : break ; case 'S' : case 's' : { if (!uint0_scan(l.arg, &nmin)) strerr_dieusage(100, USAGE) ; flagpushenv = 3 + (opt == 's') ; break ; } default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (stringarg) { nc = el_parse_from_string(&sa, stringarg) ; switch (nc) { case -4: strerr_dief2x(100, "unmatched ", "}") ; case -3: strerr_dief2x(100, "unmatched ", "{") ; case -2: strerr_dief1x(100, "syntax error") ; case -1: strerr_diefu1sys(111, "parse script") ; case 0 : return 0 ; } } else { char buf[BUFFER_INSIZE] ; buffer b ; int fd ; if (!argc--) strerr_dieusage(100, USAGE) ; dollar0 = *argv++ ; fd = openb_read(dollar0) ; if (fd < 0) strerr_diefu3sys(111, "open ", dollar0, " for reading") ; buffer_init(&b, &fd_readv, fd, buf, BUFFER_INSIZE) ; nc = el_parse_from_buffer(&sa, &b) ; fd_close(fd) ; switch (nc) { case -4: strerr_dief4x(100, "unmatched ", "}", " in file ", dollar0) ; case -3: strerr_dief4x(100, "unmatched ", "{", " in file ", dollar0) ; case -2: strerr_dief3x(100, "syntax error", " in file ", dollar0) ; case -1: strerr_diefu3sys(111, "parse script", " in file ", dollar0) ; case 0 : return 0 ; } } if (flagstrict >= 0) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, (unsigned int)flagstrict)] = 0 ; if (!env_addmodif(&modif, "EXECLINE_STRICT", flagstrict ? fmt : 0)) goto errenv ; } else { char const *x = getenv("EXECLINE_STRICT") ; if (x) { unsigned int u ; if (!uint0_scan(x, &u)) { strerr_warnw1x("invalid EXECLINE_STRICT value, unsetting it") ; if (!env_addmodif(&modif, "EXECLINE_STRICT", 0)) goto errenv ; } else flagstrict = u ; } } if (flagpushenv == 3 || flagpushenv == 4) { if (flagstrict && ((unsigned int)argc < nmin)) { char fmtn[UINT_FMT] ; char fmta[UINT_FMT] ; fmtn[uint_fmt(fmtn, nmin)] = 0 ; fmta[uint_fmt(fmta, argc)] = 0 ; if (flagstrict > 1) strerr_dief4x(100, "too few arguments: expecting at least ", fmtn, " but got ", fmta) ; else strerr_warnw4x("too few arguments: expecting at least ", fmtn, " but got ", fmta) ; } nc = myexlp(&sa, argv, argc, nmin, dollar0, flagpushenv == 4) ; if (nc < 0) strerr_diefu1sys(111, "substitute positional parameters") ; if (!nc) return 0 ; flagpushenv = 0 ; } else if (flagpushenv) { char fmt[UINT_FMT] ; unsigned int i = 0 ; fmt[uint_fmt(fmt, argc)] = 0 ; if (!env_addmodif(&modif, "#", fmt) || !env_addmodif(&modif, "0", dollar0)) goto errenv ; for (; i < (unsigned int)argc ; i++) { fmt[uint_fmt(fmt, i+1)] = 0 ; if (!env_addmodif(&modif, fmt, argv[i])) goto errenv ; } } { char const *v[nc+1] ; if (!env_make(v, nc, sa.s, sa.len)) strerr_diefu1sys(111, "make argv") ; v[nc] = 0 ; if (flagpushenv > 1) { static char const *const list[11] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "#" } ; size_t envlen = env_len(envp) ; char const *w[envlen] ; if (el_pushenv(&satmp, envp, envlen, list, 11) < 0 || !env_make(w, envlen, satmp.s, satmp.len)) goto errenv ; xmexec_fm(v, w, envlen, modif.s, modif.len) ; } else if (modif.len) xmexec_em(v, envp, modif.s, modif.len) ; else xexec_e(v, envp) ; } errenv: strerr_diefu1sys(111, "update environment") ; } execline-2.9.4.0/src/execline/exit.c000066400000000000000000000004771452216466500172030ustar00rootroot00000000000000/* ISC license. */ #include #include #include #define USAGE "exit [ exitcode ]" int main (int argc, char const *const *argv) { unsigned int e ; PROG = "exit" ; if (argc < 2) return 0 ; if (!uint0_scan(argv[1], &e)) strerr_dieusage(100, USAGE) ; _exit(e) ; } execline-2.9.4.0/src/execline/export.c000066400000000000000000000011571452216466500175470ustar00rootroot00000000000000/* ISC license. */ #include #include #include #define USAGE "export variable value prog..." int main (int argc, char const *const *argv) { size_t len1 ; PROG = "export" ; if (argc < 4) strerr_dieusage(100, USAGE) ; len1 = strlen(argv[1]) ; if (memchr(argv[1], '=', len1)) strerr_dief2x(100, "invalid variable name: ", argv[1]) ; { size_t len2 = strlen(argv[2]) ; char fmt[len1 + len2 + 2] ; memcpy(fmt, argv[1], len1) ; fmt[len1] = '=' ; memcpy(fmt + len1 + 1, argv[2], len2 + 1) ; xmexec_n(argv+3, fmt, len1 + len2 + 2, 1) ; } } execline-2.9.4.0/src/execline/fdblock.c000066400000000000000000000014741452216466500176340ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #define USAGE "fdblock [ -n ] fd prog..." int main (int argc, char const *const *argv) { unsigned int fd ; int block = 1 ; PROG = "fdblock" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "n", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : block = 0 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if ((argc < 2) || !uint0_scan(argv[0], &fd)) strerr_dieusage(100, USAGE) ; if ((block ? ndelay_off(fd) : ndelay_on(fd)) < 0) strerr_diefu1sys(111, block ? "ndelay_off" : "ndelay_on") ; xexec(argv+1) ; } execline-2.9.4.0/src/execline/fdclose.c000066400000000000000000000005611452216466500176430ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "fdclose fd prog..." int main (int argc, char const *const *argv) { unsigned int fd ; PROG = "fdclose" ; if ((argc < 3) || !uint0_scan(argv[1], &fd)) strerr_dieusage(100, USAGE) ; fd_close(fd) ; xexec(argv+2) ; } execline-2.9.4.0/src/execline/fdmove.c000066400000000000000000000015771452216466500175140ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #define USAGE "fdmove [ -c ] to from prog..." int main (int argc, char const *const *argv) { unsigned int to, from ; int flagcopy = 0 ; PROG = "fdmove" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "c", &l) ; if (opt == -1) break ; switch (opt) { case 'c' : flagcopy = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if ((argc < 3) || !uint0_scan(argv[0], &to) || !uint0_scan(argv[1], &from)) strerr_dieusage(100, USAGE) ; if ((flagcopy ? fd_copy(to, from) : fd_move(to, from)) == -1) strerr_diefu4sys(111, "move fd ", argv[1], " to fd ", argv[0]) ; xexec(argv+2) ; } execline-2.9.4.0/src/execline/fdreserve.c000066400000000000000000000031601452216466500202070ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "fdreserve n prog..." #define MAXFDS 1024 unsigned int fdreserve_doit (char *modif, unsigned int i, int fd) { unsigned int pos = 2 ; modif[0] = 'F' ; modif[1] = 'D' ; pos += uint_fmt(modif + pos, i) ; modif[pos++] = '=' ; pos += uint_fmt(modif + pos, (unsigned int)fd) ; modif[pos++] = 0 ; return pos ; } int main (int argc, char const *const *argv) { unsigned int n ; PROG = "fdreserve" ; if ((argc < 3) || !uint0_scan(argv[1], &n)) strerr_dieusage(100, USAGE) ; { struct rlimit lim ; if (getrlimit(RLIMIT_NOFILE, &lim) < 0) strerr_diefu1sys(111, "getrlimit") ; if (n > lim.rlim_cur) strerr_dief1x(100, "too many requested fds") ; } { char modif[12 * n] ; /* enough for n times "FDaaaa=bbbb\0" */ unsigned int j = 0 ; { int fd[n >> 1][2] ; unsigned int i = 0 ; for (; i < (n>>1) ; i++) if (pipe(fd[i]) < 0) strerr_diefu1sys(111, "reserve fds") ; if (n & 1) { int lastfd = openb_read("/dev/null") ; if (lastfd < 0) strerr_diefu1sys(111, "reserve last fd") ; fd_close(lastfd) ; j += fdreserve_doit(modif + j, n-1, lastfd) ; } for (i = 0 ; i < (n>>1) ; i++) { fd_close(fd[i][0]) ; fd_close(fd[i][1]) ; j += fdreserve_doit(modif + j, i<<1, fd[i][0]) ; j += fdreserve_doit(modif + j, (i<<1)|1, fd[i][1]) ; } } xmexec_n(argv+2, modif, j, n) ; } } execline-2.9.4.0/src/execline/fdswap.c000066400000000000000000000007301452216466500175060ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "fdswap fd1 fd2 prog..." int main (int argc, char const *const *argv) { unsigned int fd1, fd2 ; PROG = "fdswap" ; if ((argc < 4) || !uint0_scan(argv[1], &fd1) || !uint0_scan(argv[2], &fd2)) strerr_dieusage(100, USAGE) ; if (fd_move2(fd1, fd2, fd2, fd1) < 0) strerr_diefu1sys(111, "swap fds") ; xexec(argv+3) ; } execline-2.9.4.0/src/execline/forbacktickx.c000066400000000000000000000064571452216466500207100ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #define USAGE "forbacktickx [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -E | -e ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var { backtickcmd... } command..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { char const *delim = "\n" ; char const *codes = 0 ; int crunch = 0, chomp = 1, not = 1, par = 0, doimport = 0 ; PROG = "forbacktickx" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:Ee", &l) ; if (opt == -1) break ; switch (opt) { case 'p' : par = 1 ; break ; case 'N' : chomp = 0 ; break ; case 'n' : chomp = 1 ; break ; case 'C' : crunch = 1 ; break ; case 'c' : crunch = 0 ; break ; case '0' : delim = 0 ; break ; case 'd' : delim = l.arg ; break ; case 'o' : { unsigned short okcodes[256] ; size_t nbc ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; codes = l.arg ; not = 0 ; break ; } case 'x' : { unsigned short okcodes[256] ; size_t nbc ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; codes = l.arg ; not = 1 ; break ; } case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (!argv[0][0]) dieusage() ; if (!argv[1][0]) strerr_dief1x(100, "empty block") ; { unsigned int m = 0, i = 1 ; int fd = dup(0) ; char const *newargv[argc + 19] ; char fmt[UINT_FMT] ; if (fd < 0) { if (errno != EBADF) strerr_diefu1sys(111, "dup stdin") ; } else fmt[uint_fmt(fmt, (unsigned int)fd)] = 0 ; newargv[m++] = EXECLINE_BINPREFIX "pipeline" ; newargv[m++] = "--" ; while (argv[i] && argv[i][0] != EXECLINE_BLOCK_END_CHAR && (!EXECLINE_BLOCK_END_CHAR || (argv[i][0] && argv[i][1]))) newargv[m++] = argv[i++] ; if (!argv[i]) strerr_dief1x(100, "unterminated block") ; newargv[m++] = "" ; i++ ; newargv[m++] = EXECLINE_BINPREFIX "unexport" ; newargv[m++] = "!" ; newargv[m++] = EXECLINE_BINPREFIX "forstdin" ; newargv[m++] = doimport ? "-E" : "-e" ; if (par) newargv[m++] = "-p" ; newargv[m++] = chomp ? "-n" : "-N" ; if (crunch) newargv[m++] = "-C" ; if (!delim) newargv[m++] = "-0" ; else if (strcmp(delim, "\n")) { newargv[m++] = "-d" ; newargv[m++] = delim ; } if (codes) { newargv[m++] = not ? "-x" : "-o" ; newargv[m++] = codes ; } newargv[m++] = "--" ; newargv[m++] = argv[0] ; if (fd < 0) { newargv[m++] = EXECLINE_BINPREFIX "fdclose" ; newargv[m++] = "0" ; } else { newargv[m++] = EXECLINE_BINPREFIX "fdmove" ; newargv[m++] = "0" ; newargv[m++] = fmt ; } while (argv[i]) newargv[m++] = argv[i++] ; newargv[m++] = 0 ; xexec(newargv) ; } } execline-2.9.4.0/src/execline/foreground.c000066400000000000000000000005371452216466500204010ustar00rootroot00000000000000/* ISC license. */ #include #include int main (int argc, char const **argv, char const *const *envp) { int argc1 ; PROG = "foreground" ; argc1 = el_semicolon(++argv) ; if (argc1 >= --argc) strerr_dief1x(100, "unterminated block") ; argv[argc1] = 0 ; el_execsequence(argv, argv+argc1+1, envp) ; } execline-2.9.4.0/src/execline/forstdin.c000066400000000000000000000102331452216466500200510ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define USAGE "forstdin [ -E | -e ] [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var command..." #define dieusage() strerr_dieusage(100, USAGE) static genalloc *forstdin_pids_p = 0 ; /* minimize bss/data */ static int fs_isok (unsigned short *tab, unsigned int n, int code) { unsigned int i = 0 ; for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ; return i < n ; } static void parallel_sigchld_handler (int sig) { pid_t *tab = genalloc_s(pid_t, forstdin_pids_p) ; size_t len = genalloc_len(pid_t, forstdin_pids_p) ; int wstat ; for (;;) { ssize_t r = wait_pids_nohang(tab, len, &wstat) ; if (r <= 0) break ; tab[r-1] = tab[--len] ; } genalloc_setlen(pid_t, forstdin_pids_p, len) ; (void)sig ; } int main (int argc, char const **argv) { genalloc pids = GENALLOC_ZERO ; stralloc value = STRALLOC_ZERO ; char const *delim = "\n" ; size_t delimlen = 1 ; size_t nbc = 0 ; unsigned short okcodes[256] ; int crunch = 0, chomp = 1, not = 1, eofcode = 1, doimport = 0 ; PROG = "forstdin" ; forstdin_pids_p = &pids ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:Ee", &l) ; if (opt == -1) break ; switch (opt) { case 'p' : { if (!genalloc_ready(pid_t, &pids, 1)) strerr_diefu1sys(111, "genalloc_ready") ; break ; } case 'N' : chomp = 0 ; break ; case 'n' : chomp = 1 ; break ; case 'C' : crunch = 1 ; break ; case 'c' : crunch = 0 ; break ; case '0' : delim = "" ; delimlen = 1 ; break ; case 'd' : delim = l.arg ; delimlen = strlen(delim) ; break ; case 'o' : not = 0 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; case 'x' : not = 1 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; if (pids.s) { if (!sig_catch(SIGCHLD, ¶llel_sigchld_handler)) strerr_diefu1sys(111, "install SIGCHLD handler") ; } for (;;) { pid_t pid ; value.len = 0 ; if (delimlen) { int r = skagetlnsep(buffer_0, &value, delim, delimlen) ; if (!r) break ; else if (r < 0) { if (errno != EPIPE) strerr_diefu1sys(111, "skagetlnsep") ; if (chomp) break ; } if (crunch && value.len == 1) continue ; if (chomp) value.len-- ; } else { size_t unread = 0 ; if (netstring_get(buffer_0, &value, &unread) <= 0) { if (netstring_okeof(buffer_0, unread)) break ; else strerr_diefu1sys(111, "netstring_get") ; } } eofcode = 0 ; if (!stralloc_0(&value)) strerr_diefu1sys(111, "stralloc_0") ; if (pids.s) sig_block(SIGCHLD) ; pid = el_modif_and_spawn(argv + 1, argv[0], value.s, doimport) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ; if (pids.s) { if (!genalloc_append(pid_t, &pids, &pid)) strerr_diefu1sys(111, "genalloc_append") ; sig_unblock(SIGCHLD) ; } else { int wstat ; if (wait_pid(pid, &wstat) < 0) strerr_diefu2sys(111, "wait for ", argv[1]) ; if (not == fs_isok(okcodes, nbc, wait_estatus(wstat))) return wait_estatus(wstat) ; } } if (pids.s) { sigset_t empty ; sigemptyset(&empty) ; sig_block(SIGCHLD) ; for (;;) { if (!pids.len) break ; sigsuspend(&empty) ; } } return eofcode ; } execline-2.9.4.0/src/execline/forx.c000066400000000000000000000055761452216466500172150ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #define USAGE "forx [ -E | -e ] [ -p ] [ -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..." #define dieusage() strerr_dieusage(100, USAGE) static int fx_isok (unsigned short const *tab, unsigned int n, int code) { unsigned int i = 0 ; for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ; return i < n ; } static int waitn_code (unsigned short const *tab, unsigned int nbc, pid_t *pids, unsigned int n, int not) { int ok = 1 ; while (n) { int wstat ; unsigned int i = 0 ; pid_t pid = wait_nointr(&wstat) ; if (pid < 0) return -1 ; for (; i < n ; i++) if (pid == pids[i]) break ; if (i < n) { if (not == fx_isok(tab, nbc, wait_estatus(wstat))) ok = 0 ; pids[i] = pids[--n] ; } } return ok ; } int main (int argc, char const **argv) { char const *var ; unsigned short okcodes[256] ; size_t nbc = 0 ; int flagpar = 0, not = 1, doimport = 0 ; unsigned int argc1 ; PROG = "forx" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "po:x:Ee", &l) ; if (opt == -1) break ; switch (opt) { case 'p' : flagpar = 1 ; break ; case 'o' : not = 0 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; case 'x' : not = 1 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; var = *argv++ ; argc-- ; argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (!argc1 || (argc1 + 1 == argc)) return 0 ; { pid_t pids[flagpar ? argc1 : 1] ; for (unsigned int i = 0 ; i < argc1 ; i++) { pid_t pid = el_modif_and_spawn(argv + argc1 + 1, var, argv[i], doimport) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ; if (flagpar) pids[i] = pid ; else { int wstat ; if (wait_pid(pid, &wstat) == -1) strerr_diefu2sys(111, "wait for ", argv[argc1+1]) ; if (not == fx_isok(okcodes, nbc, wait_estatus(wstat))) return wait_estatus(wstat) ; } } if (flagpar) { int r = waitn_code(okcodes, nbc, pids, argc1, not) ; if (r < 0) strerr_diefu1sys(111, "waitn") ; else if (!r) return 1 ; } } return 0 ; } execline-2.9.4.0/src/execline/getcwd.c000066400000000000000000000017521452216466500175040ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "getcwd [ -E | -e ] variable prog..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { int doimport = 0 ; stralloc sa = STRALLOC_ZERO ; PROG = "getcwd" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "Ee", &l) ; if (opt == -1) break ; switch (opt) { case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; if (sagetcwd(&sa) < 0 || !stralloc_0(&sa)) strerr_diefu1sys(111, "getcwd") ; el_modif_and_exec(argv + 1, argv[0], sa.s, doimport) ; } execline-2.9.4.0/src/execline/getpid.c000066400000000000000000000020561452216466500175010ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "getpid [ -E | -e ] [ -P | -p ] variable prog..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { int doimport = 0 ; int doppid = 0 ; char fmt[PID_FMT] ; PROG = "getpid" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "EePp", &l) ; if (opt == -1) break ; switch (opt) { case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; case 'P' : doppid = 1 ; break ; case 'p' : doppid = 0 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; fmt[pid_fmt(fmt, doppid ? getppid() : getpid())] = 0 ; el_modif_and_exec(argv + 1, argv[0], fmt, doimport) ; } execline-2.9.4.0/src/execline/heredoc.c000066400000000000000000000026571452216466500176450ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #define USAGE "heredoc [ -d ] fd string command..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { int df = 0 ; PROG = "heredoc" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "d", &l) ; if (opt == -1) break ; switch (opt) { case 'd' : df = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 3) dieusage() ; { int fd[2] ; unsigned int fdr ; pid_t pid ; if (!uint0_scan(argv[0], &fdr)) strerr_dieusage(100, USAGE) ; if (pipe(fd) < 0) strerr_diefu1sys(111, "pipe") ; pid = df ? doublefork() : fork() ; switch (pid) { case -1: strerr_diefu2sys(111, df ? "double" : "", "fork") ; case 0: { size_t len = strlen(argv[1]) ; PROG = "heredoc (child)" ; fd_close(fd[0]) ; if (allwrite(fd[1], argv[1], len) < len) strerr_diefu1sys(111, "allwrite") ; return 0 ; } } fd_close(fd[1]) ; if (fd_move(fdr, fd[0]) == -1) strerr_diefu2sys(111, "read on fd ", argv[0]) ; } xexec(argv+2) ; } execline-2.9.4.0/src/execline/homeof.c000066400000000000000000000012211452216466500174730ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "homeof user" int main (int argc, char const *const *argv) { struct passwd *pw ; PROG = "homeof" ; if (argc < 2) strerr_dieusage(100, USAGE) ; pw = getpwnam(argv[1]) ; if (!pw) { if (errno) strerr_diefu2sys(111, "get passwd entry for ", argv[1]) ; else strerr_diefu3x(111, "get passwd entry for ", argv[1], ": no such user") ; } if ((buffer_puts(buffer_1small, pw->pw_dir) < 0) || (buffer_putflush(buffer_1small, "\n", 1) < 0)) strerr_diefu1sys(111, "write to stdout") ; return 0 ; } execline-2.9.4.0/src/execline/if.c000066400000000000000000000031711452216466500166220ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #define USAGE "if [ -n ] [ -X ] [ -t | -x exitcode ] { command... }" #define dieusage() strerr_dieusage(100, USAGE) ; int main (int argc, char const **argv, char const *const *envp) { int argc1, wstat ; pid_t pid ; int not = 0, fixed = 0, flagnormalcrash = 0 ; unsigned short e = 1 ; PROG = "if" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "nXtx:", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : not = 1 ; fixed = 1 ; break ; case 'X' : flagnormalcrash = 1 ; break ; case 't' : e = 0 ; fixed = 1 ; break ; case 'x' : if (!ushort_scan(l.arg, &e)) dieusage() ; fixed = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (e > 255) strerr_dief1x(100, "invalid exit code") ; argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; argv[argc1] = 0 ; pid = el_spawn0(argv[0], argv, envp) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; if (wait_pid(pid, &wstat) == -1) strerr_diefu1sys(111, "wait_pid") ; if (!flagnormalcrash && WIFSIGNALED(wstat)) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ; strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ; } if (not == !wait_estatus(wstat)) return fixed ? e : wait_estatus(wstat) ; xexec0_e(argv+argc1+1, envp) ; } execline-2.9.4.0/src/execline/ifelse.c000066400000000000000000000031511452216466500174710ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #define USAGE "ifelse [ -n ] [ -X ] { command-if } { command-then... } command-else..." int main (int argc, char const **argv, char const *const *envp) { int argc1, argc2, wstat ; int not = 0, flagnormalcrash = 0 ; pid_t pid ; PROG = "ifelse" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "nX", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : not = 1 ; break ; case 'X' : flagnormalcrash = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated if block") ; if (argc1 + 1 == argc) strerr_dief1x(100, "then block required") ; argc2 = el_semicolon(argv + argc1 + 1) ; if (argc1 + argc2 + 1 >= argc) strerr_dief1x(100, "unterminated then block") ; argv[argc1] = 0 ; pid = el_spawn0(argv[0], argv, envp) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; if (wait_pid(pid, &wstat) == -1) strerr_diefu2sys(111, "wait for ", argv[0]) ; argv += ++argc1 ; if (!flagnormalcrash && WIFSIGNALED(wstat)) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ; strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ; } if (not != !wait_estatus(wstat)) argv[argc2] = 0 ; else argv += argc2+1 ; xexec0_e(argv, envp) ; } execline-2.9.4.0/src/execline/ifte.c000066400000000000000000000037531452216466500171610ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #define USAGE "ifte [ -X ] [ -n ] { command-then... } { command-else... } command-if..." int main (int argc, char const **argv, char const *const *envp) { int argc1, argc2, wstat ; int not = 0, flagnormalcrash = 0 ; pid_t pid ; PROG = "ifte" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "Xn", &l) ; if (opt == -1) break ; switch (opt) { case 'X' : flagnormalcrash = 1 ; break ; case 'n' : not = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated then block") ; if (argc1 + 1 == argc) strerr_dief1x(100, "else block required") ; argc2 = el_semicolon(argv + argc1 + 1) ; if (argc1 + argc2 + 1 >= argc) strerr_dief1x(100, "unterminated else block") ; if (argc1 + argc2 + 2 >= argc) strerr_dief1x(100, "empty command-if") ; pid = el_spawn0(argv[argc1 + argc2 + 2], argv + argc1 + argc2 + 2, envp) ; if (!pid) { if (errno == ENOENT && argv[argc1 + argc2 + 2][0] == ' ') strerr_diefu3x(111, "spawn ", argv[argc1 + argc2 + 2], ": name begins with a space, are you trying to spawn a block as your command-if?") ; else strerr_diefu2sys(111, "spawn ", argv[argc1 + argc2 + 2]) ; } if (wait_pid(pid, &wstat) == -1) strerr_diefu2sys(111, "wait for ", argv[argc1 + argc2 + 2]) ; if (!flagnormalcrash && WIFSIGNALED(wstat)) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ; strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ; } if (not == !wait_estatus(wstat)) { argv += argc1 + 1 ; argv[argc2] = 0 ; } else argv[argc1] = 0 ; xexec0_e(argv, envp) ; } execline-2.9.4.0/src/execline/ifthenelse.c000066400000000000000000000042651452216466500203570ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #define USAGE "ifthenelse [ -X ] { command-if... } { command-then... } { command-else... } [ remainder... ]" int main (int argc, char const **argv, char const *const *envp) { int argc1, argc2, argc3, wstat ; int magicscope = 0, flagnormalcrash = 0 ; pid_t pid ; PROG = "ifthenelse" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "Xs", &l) ; if (opt == -1) break ; switch (opt) { case 'X' : flagnormalcrash = 1 ; break ; case 's' : magicscope = 1 ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated if block") ; if (argc1 + 1 == argc) strerr_dief1x(100, "then block required") ; argc2 = el_semicolon(argv + argc1 + 1) ; if (argc1 + argc2 + 1 >= argc) strerr_dief1x(100, "unterminated then block") ; argc3 = el_semicolon(argv + argc1 + argc2 + 2) ; if (argc1 + argc2 + argc3 + 2 >= argc) strerr_dief1x(100, "unterminated else block") ; argv[argc1] = 0 ; pid = el_spawn0(argv[0], argv, envp) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; if (wait_pid(pid, &wstat) == -1) strerr_diefu2sys(111, "wait for ", argv[0]) ; argv += argc1 + 1 ; { char const *const *remainder = argv + argc2 + argc3 + 2 ; if (!flagnormalcrash && WIFSIGNALED(wstat)) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ; strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ; } if (wait_estatus(wstat)) { argv += argc2 + 1 ; argc2 = argc3 ; } if (magicscope) /* undocumented on purpose: powerful but dangerous */ { unsigned int i = 0 ; for (; remainder[i] ; i++) argv[argc2+i] = remainder[i] ; argv[argc2+i] = 0 ; xexec0_e(argv, envp) ; } else { argv[argc2] = 0 ; el_execsequence(argv, remainder, envp) ; } } } execline-2.9.4.0/src/execline/importas.c000066400000000000000000000005101452216466500200540ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" #define USAGE "importas [ -i | -D default ] [ -u ] [ -N | -n ] [ -s ] [ -C | -c ] [ -d delim ] key var prog..." int main (int argc, char const **argv, char const *const *envp) { PROG = "importas" ; exlsn_main(argc, argv, envp, &exlsn_importas, USAGE) ; } execline-2.9.4.0/src/execline/loopwhilex.c000066400000000000000000000035051452216466500204170ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "loopwhilex [ -n ] [ -o okcode,okcode,... | -x exitcode,exitcode,... ] prog..." #define dieusage() strerr_dieusage(100, USAGE) static int lw_isok (unsigned short *tab, unsigned int n, int code) { unsigned int i = 0 ; for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ; return i < n ; } int main (int argc, char const *const *argv, char const *const *envp) { int wstat ; int not = 0, cont = 1, rev = 0 ; unsigned short okcodes[256] ; size_t nbc = 0 ; PROG = "loopwhilex" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "no:x:", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : not = 1 ; break ; case 'o' : rev = 0 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; case 'x' : rev = 1 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) dieusage() ; if (!nbc) { okcodes[0] = 0 ; nbc = 1 ; } else if (rev) not = !not ; while (cont) { pid_t pid = el_spawn0(argv[0], argv, envp) ; if (!pid) { if (errno == ENOENT && argv[0][0] == ' ') strerr_diefu3x(111, "spawn ", argv[0], ": name begins with a space, are you trying to spawn a block as your loop body?") ; else strerr_diefu2sys(111, "spawn ", argv[0]) ; } if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ; cont = not != lw_isok(okcodes, nbc, wait_estatus(wstat)) ; } return wait_estatus(wstat) ; } execline-2.9.4.0/src/execline/multidefine.c000066400000000000000000000005071452216466500205310ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" #define USAGE "multidefine [ -0 ] [ -r ] [ -N | -n ] [ -C | -c ] [ -d delim ] value { vars... } prog..." int main (int argc, char const **argv, char const *const *envp) { PROG = "multidefine" ; exlsn_main(argc, argv, envp, &exlsn_multidefine, USAGE) ; } execline-2.9.4.0/src/execline/multisubstitute.c000066400000000000000000000030511452216466500215070ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include "exlsn.h" #define USAGE "see http://skarnet.org/software/execline/multisubstitute.html" int main (int argc, char const **argv, char const *const *envp) { static char const *const commands[] = { "define", "importas", "elglob", "elgetpositionals", "multidefine", 0 } ; static exls_func_ref const functions[] = { &exlsn_define, &exlsn_importas, &exlsn_elglob, &exlsn_exlp, &exlsn_multidefine, 0 } ; exlsn_t info = EXLSN_ZERO ; int argc1 ; PROG = "multisubstitute" ; if (!--argc) strerr_dieusage(100, USAGE) ; argc1 = el_semicolon(++argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (argc1 + 1 == argc) strerr_dieusage(100, USAGE) ; while (argc1) { int n ; unsigned int i = 0 ; for (; commands[i] ; i++) if (!strcmp(*argv, commands[i])) break ; if (!commands[i]) strerr_dief3x(100, "syntax error: unrecognized", " directive ", *argv) ; n = (*(functions[i]))(argc1, argv, envp, &info) ; if (n < 0) switch (n) { case -3 : strerr_dief3x(100, "syntax error at", " directive ", commands[i]) ; case -2 : strerr_dief3x(100, "wrong key for", " directive ", commands[i]) ; case -1 : strerr_diefu3sys(111, "run", " directive ", commands[i]) ; default : strerr_dief3x(111, "unknown error with", " directive ", commands[i]) ; } argv += n ; argc1 -= n ; argc -= n ; } el_substandrun(argc-1, argv+1, envp, &info) ; } execline-2.9.4.0/src/execline/pipeline.c000066400000000000000000000033551452216466500200350ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #define USAGE "pipeline [ -d ] [ -r | -w ] { command... } command..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const **argv, char const *const *envp) { cspawn_fileaction fa[2] = { [0] = { .type = CSPAWN_FA_CLOSE }, [1] = { .type = CSPAWN_FA_MOVE } } ; pid_t pid ; int p[2] ; int argc1 ; int df = 0, w = 0 ; size_t i = 2 ; char fmt[PID_FMT + 2] = "!=" ; PROG = "pipeline" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "drw", &l) ; if (opt == -1) break ; switch (opt) { case 'd' : df = 1 ; break ; case 'r' : w = 0 ; break ; case 'w' : w = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } argc1 = el_semicolon(argv) ; if (!argc1) strerr_dief1x(100, "empty block") ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (argc1 + 1 == argc) strerr_dief1x(100, "empty remainder") ; argv[argc1] = 0 ; if (pipe(p) == -1) strerr_diefu1sys(111, "create pipe") ; fa[0].x.fd = p[w] ; fa[1].x.fd2[0] = !w ; fa[1].x.fd2[1] = p[!w] ; pid = df ? gcspawn(argv[0], argv, envp, 0, fa, 2) : cspawn(argv[0], argv, envp, 0, fa, 2) ; if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; fd_close(p[!w]) ; if (fd_move(w, p[w]) == -1) strerr_diefu1sys(111, "fd_move") ; if (w == p[w]) uncoe(w) ; i += pid_fmt(fmt+i, pid) ; fmt[i++] = 0 ; xmexec_en(argv + argc1 + 1, envp, fmt, i, 1) ; } execline-2.9.4.0/src/execline/piperw.c000066400000000000000000000013021452216466500175240ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #define USAGE "piperw fdr fdw prog..." int main (int argc, char const *const *argv) { int fdr, fdw ; int p[2] ; PROG = "piperw" ; if ((argc < 4) || !uint0_scan(argv[1], (unsigned int *)&fdr) || !uint0_scan(argv[2], (unsigned int *)&fdw) || (fdr == fdw)) strerr_dieusage(100, USAGE) ; if (pipe(p) == -1) strerr_diefu1sys(111, "create pipe") ; if (p[1] == fdr) p[1] = dup(p[1]) ; if ((p[1] == -1) || (fd_move(fdr, p[0]) == -1) || (fd_move(fdw, p[1]) == -1)) strerr_diefu1sys(111, "move fds") ; xexec(argv+3) ; } execline-2.9.4.0/src/execline/posix-cd.c000066400000000000000000000076501452216466500177600ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USAGE "posix-cd [ -L | -P ] [ - | path ] [ prog... ]" #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "stralloc_catb") int main (int argc, char const **argv) { int phy = 0 ; int dopwd = 0 ; char const *where ; int got = 0 ; stralloc sa = STRALLOC_ZERO ; PROG = "posix-cd" ; setlocale(LC_ALL, "") ; /* yeah, as if */ { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "LP", &l) ; if (opt == -1) break ; switch (opt) { case 'L' : phy = 0 ; break ; case 'P' : phy = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) where = getenv("HOME") ; else { where = *argv++ ; if (!strcmp(where, "-")) { where = getenv("OLDPWD") ; dopwd = 1 ; } } if (!where || !where[0]) dieusage() ; if (!(where[0] == '/' || (where[0] == '.' && (!where[1] || where[1] == '/' || (where[1] == '.' && (!where[2] || where[2] == '/')))))) { char const *cdpath = getenv("CDPATH") ; if (cdpath) { size_t pos = 0 ; size_t len = strlen(cdpath) ; while (pos < len) { struct stat st ; size_t m = byte_chr(cdpath + pos, len - pos, ':') ; sa.len = 0 ; if (m) { if (!stralloc_catb(&sa, cdpath + pos, m)) dienomem() ; if (cdpath[pos + m - 1] != '/' && !stralloc_catb(&sa, "/", 1)) dienomem() ; } else if (!stralloc_catb(&sa, "./", 2)) dienomem() ; if (!stralloc_cats(&sa, where) || !stralloc_0(&sa)) dienomem() ; if (!stat(sa.s, &st) && S_ISDIR(st.st_mode)) { got = 1 ; dopwd = 1 ; break ; } pos += m+1 ; } } } if (!got && (!stralloc_cats(&sa, where) || !stralloc_0(&sa))) dienomem() ; { size_t sabase = sa.len ; if (sagetcwd(&sa) < 0) strerr_diefu1sys(111, "getcwd") ; if (!stralloc_0(&sa)) dienomem() ; if (!env_mexec("OLDPWD", sa.s + sabase)) dienomem() ; sa.len = sabase ; } if (!phy) { char const *x = getenv("PWD") ; if (x && sa.s[0] != '/') { size_t len = strlen(x) ; int doslash = len && x[len-1] != '/' ; if (!stralloc_insertb(&sa, 0, x, len + doslash)) dienomem() ; if (doslash) sa.s[len] = '/' ; } { stralloc tmp = STRALLOC_ZERO ; if (!stralloc_ready(&tmp, sa.len + 2)) dienomem() ; tmp.len = path_canonicalize(tmp.s, sa.s, 1) ; if (!tmp.len++) strerr_diefu4sys(111, "canonicalize ", sa.s, ": problem with ", tmp.s) ; stralloc_free(&sa) ; sa = tmp ; } if (!env_mexec("PWD", sa.s)) dienomem() ; #ifdef PATH_MAX if (sa.len > PATH_MAX && strlen(where) < PATH_MAX && x && *x) { size_t len = strlen(x) ; int hasslash = x[len-1] == '/' ; if (!strncmp(sa.s, x, len)) { if (hasslash || (sa.len > len && sa.s[len] == '/')) { sa.len -= len + !hasslash ; memmove(sa.s, sa.s + len + !hasslash, sa.len) ; } } } #endif } /* fking finally */ if (chdir(sa.s) < 0) strerr_diefu2sys(111, "chdir to ", where) ; /* and there's still more nonsense to do afterwards! */ if (phy) { sa.len = 0 ; if (sagetcwd(&sa) < 0) strerr_diefu1sys(111, "getcwd") ; if (!stralloc_0(&sa)) dienomem() ; if (!env_mexec("PWD", sa.s)) dienomem() ; } if (dopwd) { sa.s[sa.len - 1] = '\n' ; if (allwrite(1, sa.s, sa.len) < sa.len) strerr_diefu1sys(111, "write to stdout") ; } xmexec0(argv) ; } execline-2.9.4.0/src/execline/posix-umask.c000066400000000000000000000102461452216466500205050ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #define USAGE "posix-umask [ -S ] [ mask ] [ prog... ]" #define dieusage() strerr_dieusage(100, USAGE) #define dieout() strerr_diefu1sys(111, "write to stdout") /* well, unlike posix-cd, at least this one was fun to write */ static inline int pu_output (int sym) { mode_t mode = umask(0) ; size_t m = 0 ; char fmt[18] ; if (sym) { unsigned int i = 3 ; while (i--) { unsigned int mask = ~(mode >> (3*i)) ; fmt[m++] = "ogu"[i] ; fmt[m++] = '=' ; if (mask & 4) fmt[m++] = 'r' ; if (mask & 2) fmt[m++] = 'w' ; if (mask & 1) fmt[m++] = 'x' ; if (i) fmt[m++] = ',' ; } } else m += uint0_ofmt(fmt, mode, 4) ; fmt[m++] = '\n' ; if (buffer_putflush(buffer_1, fmt, m) < 0) dieout() ; return 0 ; } static void pu_diesyntax (char const *) gccattr_noreturn ; static void pu_diesyntax (char const *s) { strerr_dief3x(101, "internal parsing error: bad ", s, ". Please submit a bug-report.") ; } static inline uint8_t pu_cclass (char c) { /* char tables may be more efficient, but this is way more readable */ switch (c) { case 0 : return 0 ; case ',' : return 1 ; case '+' : case '-' : case '=' : return 2 ; case 'u' : case 'g' : case 'o' : return 3 ; case 'a' : return 4 ; case 'r' : case 'w' : case 'x' : case 'X' : case 's' : case 't' : return 5 ; default : return 6 ; } } static inline uint8_t pu_who_value (char c) { switch (c) { case 'u' : return 4 ; case 'g' : return 2 ; case 'o' : return 1 ; case 'a' : case '+' : /* shortcut for when who is empty */ case '-' : case '=' : return 7 ; default : pu_diesyntax("who") ; } } static inline uint8_t pu_perm_value (char c) { switch (c) { case 'r' : return 4 ; case 'w' : return 2 ; case 'x' : case 'X' : return 1 ; case 's' : case 't' : return 0 ; default : pu_diesyntax("perm") ; } } static inline unsigned int pu_parsemode (char const *s) { static uint16_t const table[5][7] = { { 0x005, 0x000, 0x064, 0x021, 0x021, 0x006, 0x006 }, { 0x005, 0x006, 0x042, 0x021, 0x021, 0x006, 0x006 }, { 0x005, 0x200, 0x042, 0x083, 0x006, 0x104, 0x006 }, { 0x805, 0xe00, 0xc42, 0x006, 0x006, 0x006, 0x006 }, { 0x805, 0xe00, 0xc42, 0x006, 0x006, 0x104, 0x006 } } ; unsigned int oldmode = ~umask(0) ; uint8_t modes[3] = { oldmode & 7, (oldmode >> 3) & 7, (oldmode >> 6) & 7 } ; uint8_t who = 0 ; uint8_t perm = 0 ; uint8_t state = 0 ; char op = 0 ; while (state < 5) { char c = *s++ ; uint16_t what = table[state][pu_cclass(c)] ; state = what & 7 ; if (what & 0x020) who |= pu_who_value(c) ; if (what & 0x080) perm = modes[byte_chr("ogu", 3, c)] ; if (what & 0x100) perm |= pu_perm_value(c) ; if (what & 0x800) { unsigned int i = 3 ; while (i--) if (who & (1 << i)) switch (op) { case '-' : modes[i] &= ~perm ; break ; case '+' : modes[i] |= perm ; break ; case '=' : modes[i] = perm ; break ; default : pu_diesyntax("op") ; } } if (what & 0x040) op = c ; if (what & 0x200) who = 0 ; if (what & 0x400) perm = 0 ; } if (state > 5) strerr_dief1x(1, "invalid mode string") ; return ((unsigned int)modes[2] << 6) | ((unsigned int)modes[1] << 3) | modes[0] ; } int main (int argc, char const **argv) { int sym = 0 ; unsigned int mode ; PROG = "posix-umask" ; setlocale(LC_ALL, "") ; /* totally supported, I swear */ { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "S", &l) ; if (opt == -1) break ; switch (opt) { case 'S' : sym = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) return pu_output(sym) ; if (!uint0_oscan(argv[0], &mode)) mode = ~pu_parsemode(argv[0]) ; umask(mode & 00777) ; xexec0(argv+1) ; } execline-2.9.4.0/src/execline/posix-umask.txt000066400000000000000000000016141452216466500211010ustar00rootroot00000000000000 parsemode() function for posix-umask goal: parse the "u+r,g-wx,o=u" symbolic mode string and convert it to a numeric value suitable for umask(). In the purest skarnet.org tradition, we implement the parser via a DFA. class | 0 1 2 3 4 5 6 st\ev | \0 , +-= ugo a rwxXst other ------------------------------------------------------------------------ START | wo w w 0 | END START OP WHO WHO X X WHO | o w w 1 | END X OP WHO WHO X X OP | r o c p 2 | END START OP PERMCPY X PERM X PERMCPY | ! !rR !Ro 3 | END START OP X X X X PERM | ! !rR !Ro p 4 | END START OP X X PERM X ------------------------------------------------------------------------ END=5, X=6. -> states: 3 bits 7 actions -> 10 bits total, need uint16_t w: 0x020: who |= c o: 0x040: store op c: 0x080: copy perm from c p: 0x100: perm |= c r: 0x200: reset who R: 0x400: reset perm !: 0x800: apply (who, op, perm) change execline-2.9.4.0/src/execline/redirfd.c000066400000000000000000000040601452216466500176410ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #define USAGE "redirfd -[ r | w | u | a | x ] [ -n ] [ -b ] fd file prog..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { int fd, fd2 ; unsigned int flags = 0 ; int what = -1 ; int changemode = 0 ; PROG = "redirfd" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "rwuaxnb", &l) ; if (opt == -1) break ; switch (opt) { case 'r' : what = O_RDONLY ; flags &= ~(O_APPEND|O_CREAT|O_TRUNC|O_EXCL) ; break ; case 'w' : what = O_WRONLY ; flags |= O_CREAT|O_TRUNC ; flags &= ~(O_APPEND|O_EXCL) ; break ; case 'u' : what = O_RDWR ; flags &= ~(O_APPEND|O_CREAT|O_TRUNC|O_EXCL) ; break ; case 'a' : what = O_WRONLY ; flags |= O_CREAT|O_APPEND ; flags &= ~(O_TRUNC|O_EXCL) ; break ; case 'x' : what = O_WRONLY ; flags |= O_CREAT|O_EXCL ; flags &= ~(O_APPEND|O_TRUNC) ; break ; case 'n' : flags |= O_NONBLOCK ; break ; case 'b' : changemode = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if ((argc < 3) || (what == -1)) dieusage() ; if (!uint0_scan(argv[0], (unsigned int *)&fd)) dieusage() ; flags |= what ; fd2 = open3(argv[1], flags, 0666) ; if ((fd2 == -1) && (what == O_WRONLY) && (errno == ENXIO)) { int fdr = open_read(argv[1]) ; if (fdr == -1) strerr_diefu2sys(111, "open_read ", argv[1]) ; fd2 = open3(argv[1], flags, 0666) ; fd_close(fdr) ; } if (fd2 == -1) strerr_diefu2sys(111, "open ", argv[1]) ; if (fd_move(fd, fd2) == -1) { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, fd2)] = 0 ; strerr_diefu4sys(111, "move fd ", fmt, " to fd ", argv[0]) ; } if (changemode) { if (((flags & O_NONBLOCK) ? ndelay_off(fd) : ndelay_on(fd)) < 0) strerr_diefu1sys(111, "change blocking mode") ; } xexec(argv+2) ; } execline-2.9.4.0/src/execline/runblock.c000066400000000000000000000112021452216466500200350ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #define USAGE "runblock [ -P ] [ -n argshift ] [ -r ] n cmd..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv, char const *const *envp) { genalloc v = GENALLOC_ZERO ; /* array of char const * */ unsigned int n, sharp ; unsigned int m = 0 ; unsigned int strict = el_getstrict() ; int flagnopop = 0, flagr = 0 ; PROG = "runblock" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "Prn:", &l) ; if (opt == -1) break ; switch (opt) { case 'P' : flagnopop = 1 ; break ; case 'r' : flagr = 1 ; break ; case 'n' : if (!uint0_scan(l.arg, &m)) dieusage() ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc--) dieusage() ; if (!uint0_scan(*argv++, &n) || (!n && !flagr)) dieusage() ; { char const *x = getenv("#") ; if (!x) strerr_dienotset(100, "#") ; if (!uint0_scan(x, &sharp)) strerr_dieinvalid(100, "#") ; } /* Skip n-1 blocks (n if flagr) */ { unsigned int i = 1 ; for (; i < n + flagr ; i++) { unsigned int base = m ; for (;;) { char const *x ; char fmt[UINT_FMT] ; if (++m > sharp) strerr_dief1x(100, "too few arguments") ; fmt[uint_fmt(fmt, m)] = 0 ; x = getenv(fmt) ; if (!x) strerr_dienotset(100, fmt) ; if ((x[0] == EXECLINE_BLOCK_END_CHAR) && (!EXECLINE_BLOCK_END_CHAR || !x[1])) break ; if ((x[0] != EXECLINE_BLOCK_QUOTE_CHAR) && strict) { char fmtb[UINT_FMT] ; char fmti[UINT_FMT] ; fmti[uint_fmt(fmti, i)] = 0 ; fmtb[uint_fmt(fmtb, m - base)] = 0 ; if (strict == 1) strerr_warnw6x("unquoted positional ", x, " at block ", fmti, " position ", fmtb) ; else strerr_dief6x(100, "unquoted positional ", x, " at block ", fmti, " position ", fmtb) ; } } } } /* First put args, if any, into v */ if (!genalloc_ready(char const *, &v, argc)) strerr_diefu1sys(111, "genalloc_ready") ; for (unsigned int i = 0 ; i < (unsigned int)argc ; i++) genalloc_append(char const *, &v, argv + i) ; if (flagr) /* put remainder envvars into v */ { if (++m > sharp) return 0 ; if (!genalloc_readyplus(char const *, &v, sharp - m + 2)) strerr_diefu1sys(111, "genalloc_readyplus") ; for (; m <= sharp ; m++) { char const *x ; char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, m)] = 0 ; x = getenv(fmt) ; if (!x) strerr_dienotset(100, fmt) ; genalloc_append(char const *, &v, &x) ; } } else /* put envvars from nth block into v */ { unsigned int base = m ; for (;;) { char const *x ; char fmt[UINT_FMT] ; if (++m > sharp) strerr_dief1x(100, "too few arguments") ; fmt[uint_fmt(fmt, m)] = 0 ; x = getenv(fmt) ; if (!x) strerr_dienotset(100, fmt) ; if ((x[0] == EXECLINE_BLOCK_END_CHAR) && (!EXECLINE_BLOCK_END_CHAR || !x[1])) break ; if (x[0] != EXECLINE_BLOCK_QUOTE_CHAR) { if (strict) { char fmtb[UINT_FMT] ; char fmtn[UINT_FMT] ; fmtn[uint_fmt(fmtn, n)] = 0 ; fmtb[uint_fmt(fmtb, m - base)] = 0 ; if (strict == 1) strerr_warnw6x("unquoted positional ", x, " at block ", fmtn, " position ", fmtb) ; else strerr_dief6x(100, "unquoted positional ", x, " at block ", fmtn, " position ", fmtb) ; } } else x++ ; if (!genalloc_append(char const *, &v, &x)) strerr_diefu1sys(111, "envalloc_catb") ; } } { char const *z = 0 ; if (!genalloc_append(char const *, &v, &z)) strerr_diefu1sys(111, "genalloc_append") ; } if (flagnopop) /* exec now */ xexec_e(genalloc_s(char const *, &v), envp) ; else /* popenv, then exec */ { char const *list[11] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "#" } ; size_t envlen = env_len(envp) ; int popped = el_popenv(&satmp, envp, envlen, list, 11) ; if (popped < 0) strerr_diefu1sys(111, "pop environment") ; else { char const *w[envlen - popped + 1] ; if (!env_make(w, envlen - popped, satmp.s, satmp.len)) strerr_diefu1sys(111, "env_make") ; w[envlen - popped] = 0 ; xexec_e(genalloc_s(char const *, &v), w) ; } } } execline-2.9.4.0/src/execline/shift.c000066400000000000000000000057611452216466500173500ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "shift [ -n arg# ] [ -b block# ] prog..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { unsigned int strict = el_getstrict() ; unsigned int b = 0 ; unsigned int n = 0 ; unsigned int sharp ; unsigned int i = 0 ; PROG = "shift" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "n:b:", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : if (!uint0_scan(l.arg, &n)) dieusage() ; i = 1 ; break ; case 'b' : if (!uint0_scan(l.arg, &b)) dieusage() ; i = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) dieusage() ; if (i) i = 0 ; else n = 1 ; { char const *x = getenv("#") ; if (!x) strerr_dienotset(100, "#") ; if (!uint0_scan(x, &sharp)) strerr_dieinvalid(100, "#") ; } /* Shift n args */ if (n > sharp) { if (strict) { char fmtn[UINT_FMT] ; char fmtsharp[UINT_FMT] ; fmtn[uint_fmt(fmtn, n)] = 0 ; fmtsharp[uint_fmt(fmtsharp, sharp)] = 0 ; if (strict == 1) strerr_warnwu5x("shift", " ", fmtn, " arguments: got ", fmtsharp) ; else strerr_diefu5x(100, "shift", " ", fmtn, " arguments: got ", fmtsharp) ; } n = sharp ; } /* Shift b blocks */ for (; i < b ; i++) { for (;;) { char const *x ; unsigned int base = n ; char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, ++n)] = 0 ; if (n > sharp) { char fmti[UINT_FMT] ; fmti[uint_fmt(fmt, i)] = 0 ; strerr_diefu6x(100, "shift", " block ", fmti, ": too few arguments (", fmt, ")") ; } x = getenv(fmt) ; if (!x) strerr_dienotset(100, fmt) ; if ((x[0] == EXECLINE_BLOCK_END_CHAR) && (!EXECLINE_BLOCK_END_CHAR || !x[1])) break ; if ((x[0] != EXECLINE_BLOCK_QUOTE_CHAR) && strict) { char fmti[UINT_FMT] ; char fmtp[UINT_FMT] ; fmti[uint_fmt(fmti, i)] = 0 ; fmtp[uint_fmt(fmtp, n - base)] = 0 ; if (strict == 1) strerr_warnw6x("unquoted positional ", x, " at block ", fmti, " position ", fmtp) ; else strerr_dief6x(100, "unquoted positional ", x, " at block ", fmti, " position ", fmtp) ; } } } /* n = shift value; modify the env */ { unsigned int i = 1 ; char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, sharp - n)] = 0 ; if (!env_mexec("#", fmt)) strerr_diefu1sys(111, "env_mexec") ; for (; i <= sharp ; i++) { char fmu[UINT_FMT] ; fmt[uint_fmt(fmt, i)] = 0 ; fmu[uint_fmt(fmu, i + n)] = 0 ; if (!env_mexec(fmt, i <= (sharp - n) ? getenv(fmu) : 0)) strerr_diefu1sys(111, "modify environment") ; } } xmexec(argv) ; } execline-2.9.4.0/src/execline/trap.c000066400000000000000000000105571452216466500172000ustar00rootroot00000000000000/* ISC license. */ #include /* for SKALIBS_NSIG to work */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USAGE "trap [ -x ] { signal { cmdline } ... } prog..." #define dieusage() strerr_dieusage(100, USAGE) ; static inline void trap_action (unsigned int i, char const *const *envp, size_t envlen, pid_t *pids, char const *const **argvs) { if (argvs[i]) { if (!pids[i]) { char const *newenvp[envlen + 3] ; char modif[9 + PID_FMT + UINT_FMT] = "!=" ; size_t m = 2 ; m += pid_fmt(modif + m, pids[SKALIBS_NSIG]) ; modif[m++] = 0 ; memcpy(modif + m, "SIGNAL=", 7) ; m += 7 ; m += uint_fmt(modif + m, i) ; modif[m++] = 0 ; if (!env_mergen(newenvp, envlen + 3, envp, envlen, modif, m, 2)) strerr_diefu1sys(111, "adjust environment for child") ; pids[i] = cspawn(argvs[i][0], argvs[i], newenvp, CSPAWN_FLAGS_SELFPIPE_FINISH, 0, 0) ; if (!pids[i]) strerr_diefu2sys(111, "spawn ", argvs[i][0]) ; } } else kill(pids[SKALIBS_NSIG], i) ; } int main (int argc, char const **argv, char const *const *envp) { pid_t pids[SKALIBS_NSIG + 1] = { 0 } ; char const *const *argvs[SKALIBS_NSIG] = { 0 } ; size_t envlen = env_len(envp) ; iopause_fd x = { .events = IOPAUSE_READ } ; sigset_t full, set ; int xfersigs = 0 ; unsigned int argc1 ; unsigned int i = 0 ; PROG = "trap" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "xt:", &l) ; if (opt == -1) break ; switch (opt) { case 'x' : xfersigs = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) dieusage() ; argc1 = el_semicolon(argv) ; if (!argc1) strerr_dief1x(100, "empty block") ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (argc1 + 1 == argc) dieusage() ; argv[argc1] = 0 ; sigfillset(&full) ; sigdelset(&full, SIGKILL) ; sigdelset(&full, SIGSTOP) ; while (i < argc1) { unsigned int argc2 ; int sig = 0 ; if (!sig0_scan(argv[i], &sig) && strcasecmp(argv[i], "default")) strerr_dief3x(100, "unrecognized", " directive: ", argv[i]) ; argc2 = el_semicolon(argv + ++i) ; if (i + argc2 >= argc1) strerr_dief3x(100, "unterminated", " internal block for directive ", argv[i-1]) ; if (argvs[sig]) strerr_dief3x(100, "duplicate", " directive: ", argv[i-1]) ; if (!sig || (sig != SIGCHLD && sigismember(&full, sig) > 0)) argvs[sig] = argv + i ; else { char fmt[UINT_FMT] ; fmt[uint_fmt(fmt, (unsigned int)sig)] = 0 ; strerr_dief5x(100, "SIG", sig_name(sig), " (", fmt, ") cannot be trapped") ; } argv[i + argc2] = 0 ; i += argc2 + 1 ; } if (argvs[0]) for (i = 1 ; i < SKALIBS_NSIG ; i++) if (!argvs[i] && sigismember(&full, i) > 0) argvs[i] = argvs[0] ; if (xfersigs) set = full ; else { sigemptyset(&set) ; sigaddset(&set, SIGCHLD) ; for (i = 1 ; i < SKALIBS_NSIG ; i++) if (argvs[i]) sigaddset(&set, i) ; } x.fd = selfpipe_init() ; if (x.fd == -1) strerr_diefu1sys(111, "selfpipe_init") ; if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "trap signals") ; pids[SKALIBS_NSIG] = cspawn(argv[argc1 + 1], argv + argc1 + 1, envp, CSPAWN_FLAGS_SELFPIPE_FINISH, 0, 0) ; if (!pids[SKALIBS_NSIG]) strerr_diefu2sys(111, "spawn ", argv[argc1 + 1]) ; loop: if (iopause_g(&x, 1, 0) < 0) strerr_diefu1sys(111, "iopause") ; for (;;) { int r = selfpipe_read() ; switch (r) { case -1 : strerr_diefu1sys(111, "selfpipe_read") ; case 0 : goto loop ; case SIGCHLD : for (;;) { int wstat ; ssize_t id = wait_pids_nohang(pids, SKALIBS_NSIG + 1, &wstat) ; if (id < 0 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; if (id <= 0) break ; pids[id - 1] = 0 ; if (id == SKALIBS_NSIG + 1) return wait_estatus(wstat) ; } break ; default : trap_action(r, envp, envlen, pids, argvs) ; } } } execline-2.9.4.0/src/execline/tryexec.c000066400000000000000000000031721452216466500177100ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #define USAGE "tryexec [ -n ] [ -c ] [ -l ] [ -a argv0 ] { command... } remainder..." int main (int argc, char const **argv, char const *const *envp) { char const *env_zero[1] = { 0 } ; char const *executable = 0 ; char const *argv0 = 0 ; char const **dom = 0 ; char const **sub = 0 ; char const *const *dom_envp = envp ; int not = 0, dash = 0 ; PROG = "tryexec" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "ncla:", &l) ; if (opt == -1) break ; switch (opt) { case 'n' : not = 1 ; break ; case 'c' : dom_envp = env_zero ; break ; case 'l' : dash = 1 ; break ; case 'a' : argv0 = l.arg ; break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; } { int argc1 = el_semicolon(argv) ; if (!argc1) strerr_dief1x(100, "empty block") ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (not && argc1 == argc - 1) strerr_dief1x(100, "empty remainder not allowed with -n") ; argv[argc1] = 0 ; dom = argv + not * (argc1 + 1) ; sub = argv + !not * (argc1 + 1) ; } executable = dom[0] ; if (argv0) dom[0] = argv0 ; if (dash) { size_t n = strlen(dom[0]) ; char dashed[n+2] ; dashed[0] = '-' ; memcpy(dashed+1, dom[0], n+1) ; dom[0] = dashed ; exec_ae(executable, dom, dom_envp) ; } else exec_ae(executable, dom, dom_envp) ; xexec0_e(sub, envp) ; } execline-2.9.4.0/src/execline/unexport.c000066400000000000000000000007101452216466500201040ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #define USAGE "unexport variable prog..." int main (int argc, char const *const *argv) { size_t len ; PROG = "unexport" ; if (argc < 3) strerr_dieusage(100, USAGE) ; len = strlen(argv[1]) ; if (memchr(argv[1], '=', len)) strerr_dief2x(100, "invalid variable name: ", argv[1]) ; xmexec_n(argv+2, argv[1], len+1, 1) ; } execline-2.9.4.0/src/execline/wait.c000066400000000000000000000133421452216466500171710ustar00rootroot00000000000000/* ISC license. */ #include #include #include #ifdef EXECLINE_PEDANTIC_POSIX #include #endif #include #include #include #include #include #include #include #include #include #define USAGE "wait [ -I | -i ] [ -a | -o ] [ -r | -t timeout ] { pids... } [ prog... ]" #define dieusage() strerr_dieusage(100, USAGE) typedef int ac_func (pid_t *, unsigned int *, int *) ; typedef ac_func *ac_func_ref ; static int wait_all (void) { errno = 0 ; while (wait_nointr(0) > 0) ; if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; return 0 ; } static int wait_from_list (pid_t *pids, unsigned int n) { int wstat = -1 ; if (!waitn_posix(pids, n, &wstat) && errno != ECHILD) strerr_diefu1sys(111, "wait") ; return wstat == -1 ? -1 : wait_estatus(wstat) ; } static int wait_one (pid_t *pid) { int wstat = 0 ; *pid = wait(&wstat) ; if (*pid < 0) { if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; else return -1 ; } return wait_estatus(wstat) ; } static int wait_one_from_list (pid_t *pids, unsigned int n, pid_t *pid) { for (;;) { int wstat ; pid_t r = wait(&wstat) ; unsigned int i = 0 ; if (r < 0) { if (errno != ECHILD) strerr_diefu1sys(111, "wait") ; else return -1 ; } for (; i < n ; i++) if (r == pids[i]) break ; if (i < n) { *pid = r ; pids[i] = pids[n-1] ; return wait_estatus(wstat) ; } } } static int wait_one_nohang (pid_t *pids, unsigned int *n, int *wstat) { pid_t r = wait_nohang(wstat) ; if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; (void)pids ; (void)n ; return r ; } static int wait_one_from_list_nohang (pid_t *pids, unsigned int *n, int *wstat) { for (;;) { pid_t r = wait_nohang(wstat) ; unsigned int i = 0 ; if (r <= 0) { if (r == -1 && errno != ECHILD) strerr_diefu1sys(111, "wait") ; else return r ; } for (; i < *n ; i++) if (r == pids[i]) break ; if (i < *n) { pids[i] = pids[--*n] ; return r ; } } } static inline void empty_selfpipe (void) { for (;;) switch (selfpipe_read()) { case -1 : strerr_diefu1sys(111, "read selfpipe") ; case 0 : return ; case SIGCHLD : break ; default: strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ; } } static int wait_with_timeout (pid_t *pids, unsigned int n, pid_t *returned, ac_func_ref f, tain *tto, int justone, int strict) { iopause_fd x = { .fd = selfpipe_init(), .events = IOPAUSE_READ } ; pid_t special = pids[n-1] ; int e = special ? -1 : 0 ; if (x.fd < 0) strerr_diefu1sys(111, "create selfpipe") ; if (!selfpipe_trap(SIGCHLD)) strerr_diefu1sys(111, "trap SIGCHLD") ; tain_now_set_stopwatch_g() ; tain_add_g(tto, tto) ; for (;;) { int r ; for (;;) { int wstat ; pid_t pid = (*f)(pids, &n, &wstat) ; if (!pid) break ; if (pid < 0) goto endloop ; if (justone || pid == special) { *returned = pid ; e = wait_estatus(wstat) ; } if (justone || !n) goto endloop ; } r = iopause_g(&x, 1, tto) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; else if (!r) { if (!strict) { e = -1 ; break ; } errno = ETIMEDOUT ; strerr_diefu1sys(99, "wait") ; } else empty_selfpipe() ; } endloop: selfpipe_finish() ; return e ; } int main (int argc, char const **argv) { tain tto ; int argc1 ; int hastimeout = 0 ; int insist = 0 ; int justone = 0 ; int hasblock ; int e ; pid_t pid = -1 ; PROG = "wait" ; #ifdef EXECLINE_PEDANTIC_POSIX setlocale(LC_ALL, "") ; /* but of course, dear POSIX */ #endif { subgetopt l = SUBGETOPT_ZERO ; unsigned int t = 0 ; for (;;) { int opt = subgetopt_r(argc, argv, "iIaort:", &l) ; if (opt == -1) break ; switch (opt) { case 'i' : insist = 1 ; break ; case 'I' : insist = 0 ; break ; case 'a' : justone = 0 ; break ; case 'o' : justone = 1 ; break ; case 'r' : t = 0 ; hastimeout = 1 ; break ; case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; hastimeout = 1 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; if (hastimeout) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; } argc1 = el_semicolon(argv) ; if (argc1 >= argc) { hasblock = 0 ; argc1 = argc ; } else hasblock = 1 ; { unsigned int n = argc1 ? argc1 : 1 ; pid_t pids[n] ; if (argc1) { unsigned int i = 0 ; for (; i < n ; i++) if (!pid0_scan(argv[i], pids + i)) strerr_dieusage(100, USAGE) ; } else pids[0] = 0 ; e = hastimeout ? /* wait -t30000 whatever */ wait_with_timeout(pids, n, &pid, argc1 ? &wait_one_from_list_nohang : &wait_one_nohang, &tto, justone, insist) : justone ? argc1 ? wait_one_from_list(pids, n, &pid) : /* wait -o -- 2 3 4 / wait -o -- { 2 3 4 } */ wait_one(&pid) : /* wait -o / wait -o { } */ argc1 ? wait_from_list(pids, n) : /* wait 2 3 4 / wait { 2 3 4 }*/ wait_all() ; /* wait / wait { } */ } if (!hasblock) return e >= 0 ? e : 127 ; if (!justone) xexec0(argv + argc1 + 1) ; if (e < 0) xmexec0_n(argv + argc1 + 1, "?\0!", 4, 2) ; { char fmt[4 + UINT_FMT + PID_FMT] = "?=" ; size_t m = 2 ; m += uint_fmt(fmt + m, (unsigned int)e) ; fmt[m++] = 0 ; fmt[m++] = '!' ; fmt[m++] = '=' ; m += pid_fmt(fmt + m, pid) ; fmt[m++] = 0 ; xmexec0_n(argv + argc1 + 1, fmt, m, 2) ; } } execline-2.9.4.0/src/execline/withstdinas.c000066400000000000000000000032611452216466500205650ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #define USAGE "withstdinas [ -i | -I | -D default ] [ -N | -n ] [ -E | -e ] var remainder..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const *const *argv) { subgetopt localopt = SUBGETOPT_ZERO ; stralloc value = STRALLOC_ZERO ; int insist = 0, chomp = 1, doimport = 0 ; char const *def = 0 ; char const *val ; PROG = "withstdinas" ; for (;;) { int opt = subgetopt_r(argc, argv, "iINnD:Ee", &localopt) ; if (opt < 0) break ; switch (opt) { case 'i' : insist = 2 ; break ; case 'I' : insist = 1 ; break ; case 'N' : chomp = 0 ; break ; case 'n' : chomp = 1 ; break ; case 'D' : def = localopt.arg ; break ; case 'E' : doimport = 1 ; break ; case 'e' : doimport = 0 ; break ; default : dieusage() ; } } argc -= localopt.ind ; argv += localopt.ind ; if (!argc) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; if (!slurp(&value, 0) || !stralloc_0(&value)) strerr_diefu1sys(111, "slurp") ; val = value.s ; if (strlen(value.s) < value.len - 1) { if (insist >= 2) strerr_dief1x(1, "stdin contained a null character") ; else if (insist) val = 0 ; else if (def) { val = def ; strerr_warnw2x("stdin contained a null character", " - using default instead") ; } } else if (chomp && (value.s[value.len - 2] == '\n')) value.s[--value.len - 1] = 0 ; el_modif_and_exec(argv + 1, argv[0], val, doimport) ; } execline-2.9.4.0/src/include-local/000077500000000000000000000000001452216466500167755ustar00rootroot00000000000000execline-2.9.4.0/src/include-local/exlsn.h000066400000000000000000000022061452216466500202770ustar00rootroot00000000000000/* ISC license. */ #ifndef EXLSN_H #define EXLSN_H #include #include #include typedef struct exlsn_s exlsn_t, *exlsn_t_ref ; struct exlsn_s { stralloc vars ; stralloc values ; genalloc data ; /* array of elsubst */ stralloc modifs ; } ; #define EXLSN_ZERO { .vars = STRALLOC_ZERO, .values = STRALLOC_ZERO, .data = GENALLOC_ZERO, .modifs = STRALLOC_ZERO } extern void exlsn_free (exlsn_t *) ; typedef int exls_func (int, char const **, char const *const *, exlsn_t *) ; typedef exls_func *exls_func_ref ; extern exls_func exlsn_define ; extern exls_func exlsn_importas ; extern exls_func exlsn_elglob ; extern exls_func exlsn_exlp ; extern exls_func exlsn_multidefine ; extern int exlp (unsigned int, char const *const *, exlsn_t *) ; extern void el_substandrun (int, char const *const *, char const *const *, exlsn_t const *) gccattr_noreturn ; extern void el_substandrun_str (stralloc *, size_t, char const *const *, exlsn_t const *) gccattr_noreturn ; extern void exlsn_main (int, char const **, char const *const *, exls_func *, char const *) gccattr_noreturn ; #endif execline-2.9.4.0/src/include/000077500000000000000000000000001452216466500157055ustar00rootroot00000000000000execline-2.9.4.0/src/include/execline/000077500000000000000000000000001452216466500175015ustar00rootroot00000000000000execline-2.9.4.0/src/include/execline/execline.h000066400000000000000000000043731452216466500214550ustar00rootroot00000000000000/* ISC license. */ #ifndef EXECLINE_H #define EXECLINE_H #include #include #include #include #define EXECLINE_BLOCK_QUOTE_STRING " " #define EXECLINE_BLOCK_QUOTE_CHAR ' ' #define EXECLINE_BLOCK_END_STRING "" #define EXECLINE_BLOCK_END_CHAR '\0' /* Parsing */ typedef int el_chargen_func (unsigned char *, void *) ; typedef el_chargen_func *el_chargen_func_ref ; extern int el_parse (stralloc *, el_chargen_func_ref, void *) ; extern int el_parse_from_string (stralloc *, char const *) ; extern int el_parse_from_buffer (stralloc *, buffer *) ; /* Basics */ extern int el_vardupl (char const *, char const *, size_t) gccattr_pure ; extern unsigned int el_getstrict (void) gccattr_const ; /* Environment shifting */ extern int el_pushenv (stralloc *, char const *const *, size_t, char const *const *, size_t) ; extern int el_popenv (stralloc *, char const *const *, size_t, char const *const *, size_t) ; /* Sequence */ extern pid_t el_spawn0 (char const *, char const *const *, char const *const *) ; extern pid_t el_spawn1 (char const *, char const *const *, char const *const *, int *, int) ; extern void el_execsequence (char const *const *, char const *const *, char const *const *) gccattr_noreturn ; /* Block unquoting */ extern int el_semicolon (char const **) ; /* Value transformation */ typedef struct eltransforminfo_s eltransforminfo_t, *eltransforminfo_t_ref ; struct eltransforminfo_s { char const *delim ; unsigned int crunch : 1 ; unsigned int chomp : 1 ; unsigned int split : 1 ; } ; #define ELTRANSFORMINFO_ZERO { .delim = " \n\r\t", .crunch = 0, .chomp = 0, .split = 0 } extern int el_transform (stralloc *, size_t, eltransforminfo_t const *) ; /* Substitution */ typedef struct elsubst_s elsubst_t, *elsubst_t_ref ; struct elsubst_s { size_t var ; size_t value ; unsigned int n ; } ; extern int el_substitute (stralloc *, char const *, size_t, char const *, char const *, elsubst_t const *, unsigned int) ; /* Execution with or without substitution */ extern void el_modif_and_exec (char const *const *, char const *, char const *, int) gccattr_noreturn ; extern pid_t el_modif_and_spawn (char const *const *, char const *, char const *, int) ; #endif execline-2.9.4.0/src/libexecline/000077500000000000000000000000001452216466500165455ustar00rootroot00000000000000execline-2.9.4.0/src/libexecline/PARSING.txt000066400000000000000000000050751452216466500204200ustar00rootroot00000000000000el_parse.c: class | 0 1 2 3 4 5 6 7 8 9 a b c d e f st\ev | \0 space # " newline \ normal abf 1-7 8-9 0 nrtv x A-Fcde { } START | n n p n p n p n p n p n p n p n p n p n p 00 | END START COMMENT Q START Q1 W W W W W W W W OPENB CLOSEB COMMENT | 01 | END COMMENT COMMENT COMMENT START COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT OPENB | { p { p p p p p p p p p p 02 | X START W Q START Q1 W W W W W W W W W W CLOSEB | } 0 } 0 p } 0 p p p p p p p p p p 03 | END START W Q START Q1 W W W W W W W W W W W | 0 0 p 0 p p p p p p p p p p 04 | END START W Q START Q2 W W W W W W W W W W Q1 | n p n p n p n p n p n p n p n p n p n p n p n p n p n p 05 | END W W W START W W W W W W W W W W W Q2 | p p p p p p p p p p p p p p p 06 | X W W W W W W W W W W W W W W W Q3 | p p p p p c m p b m p b b c p p p p 07 | X Q Q Q Q Q Q Q DEC1 DEC1 OCT Q Q Q Q Q Q | p p p p p p p p p p p p p 08 | X Q Q W Q Q3 Q Q Q Q Q Q Q Q Q Q OCT | m p m p b 09 | X X X X X X X X OCT1 X OCT1 X HEX X X X OCT1 | s 0 s p s p s s p s s p s p p s p p s p s p s p s p s p 0a | END Q Q W Q Q3 Q Q OCT2 Q OCT2 Q Q Q Q Q OCT2 | s 0 s p s p s s p s s p s p p s p p s p s p s p s p s p 0b | END Q Q W Q Q3 Q Q ENDNUM Q ENDNUM Q Q Q Q Q DEC1 | s 0 s p s p s s p s s p s p p p p s p s p s p s p s p 0c | END Q Q W Q Q3 Q Q DEC2 DEC2 DEC2 Q Q Q Q Q DEC2 | s 0 s p s p s s p s s p s p p p p s p s p s p s p s p 0d | END Q Q W Q Q3 Q Q ENDNUM ENDNUM ENDNUM Q Q Q Q Q HEX | m p m p m p m p m p 0e | X X X X X X X HEX1 HEX1 HEX1 HEX1 X X HEX1 X X HEX1 | s 0 s p s p s s p s s p p p p p s p s p p s p s p 0f | END Q Q W Q Q3 Q ENDNUM ENDNUM ENDNUM ENDNUM Q Q ENDNUM Q Q ENDNUM | s 0 s p s p s s p s s p s p s p s p s p s p s p s p s p s p 10 | END Q Q W Q Q3 Q Q Q Q Q Q Q Q Q Q END 11 X 12 States START: in whitespace; initial state COMMENT: in a comment line OPENB: after a raw { CLOSEB: after a raw } W: in an unquoted word Q1: after a backslash in whitespace Q2: after a backslash in an unquoted word Q3: after a backslash in a quoted string Q: in a quoted string OCT: after \0 OCT1: after \0a OCT2: after \0ab DEC1: after \a DEC2: after \ab HEX: after \0x HEX1: after \0xa ENDNUM: after \0abc, \abc or \0xab END: success X: syntax error Actions 8000 s scan integer from mark, push it 4000 m set mark 2000 n new word: push blevel spaces 1000 { begin block (inc blevel, unpush) 0800 } end block (dec blevel, unpush) 0400 p push cur 0200 c push control char (depending on cur) 0100 0 end word: push \0 0080 b switch base according to cur 0040 unused 0020 unused execline-2.9.4.0/src/libexecline/deps-lib/000077500000000000000000000000001452216466500202445ustar00rootroot00000000000000execline-2.9.4.0/src/libexecline/deps-lib/execline000066400000000000000000000006361452216466500217700ustar00rootroot00000000000000el_execsequence.o el_getstrict.o el_modif_and_exec.o el_modif_and_spawn.o el_parse.o el_parse_from_buffer.o el_parse_from_string.o el_popenv.o el_pushenv.o el_semicolon.o el_spawn0.o el_gspawn0.o el_substandrun.o el_substandrun_str.o el_substitute.o el_transform.o el_vardupl.o exlsn_define.o exlsn_elglob.o exlsn_importas.o exlsn_multidefine.o exlsn_exlp.o exlsn_main.o exlsn_free.o exlp.o -lskarnet ${SPAWN_LIB} execline-2.9.4.0/src/libexecline/el_execsequence.c000066400000000000000000000013421452216466500220460ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include void el_execsequence (char const *const *argv1, char const *const *argv2, char const *const *envp) { size_t j = 2 ; char fmt[UINT_FMT + 1] = "?=" ; pid_t pid = el_spawn0(argv1[0], argv1, envp) ; if (!pid) { strerr_warnwu2sys("spawn ", argv1[0]) ; memcpy(fmt+2, "127", 3) ; j += 3 ; } else { int wstat ; if (wait_pid(pid, &wstat) < 0) strerr_diefu2sys(111, "wait for ", argv1[0]) ; j += uint_fmt(fmt + j, wait_status(wstat)) ; } fmt[j++] = 0 ; xmexec0_en(argv2, envp, fmt, j, 1) ; } execline-2.9.4.0/src/libexecline/el_getstrict.c000066400000000000000000000005171452216466500214040ustar00rootroot00000000000000/* ISC license. */ #include #include #include unsigned int el_getstrict (void) { static unsigned int strict = 0 ; static int first = 1 ; if (first) { char const *x = getenv("EXECLINE_STRICT") ; first = 0 ; if (x) uint0_scan(x, &strict) ; } return strict ; } execline-2.9.4.0/src/libexecline/el_gspawn0.c000066400000000000000000000006361452216466500207550ustar00rootroot00000000000000/* ISC license. */ #include #include #include pid_t el_gspawn0 (char const *prog, char const *const *argv, char const *const *envp) { if (!argv[0]) { static char const *const newargv[3] = { EXECLINE_BINPREFIX "exit", "0", 0 } ; return gcspawn(newargv[0], newargv, envp, 0, 0, 0) ; } else return gcspawn(prog, argv, envp, 0, 0, 0) ; } execline-2.9.4.0/src/libexecline/el_modif_and_exec.c000066400000000000000000000017401452216466500223170ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include void el_modif_and_exec (char const *const *argv, char const *var, char const *value, int doimport) { size_t varlen = strlen(var) ; size_t modiflen = value ? varlen + strlen(value) + 2 : 1 ; char modifs[modiflen] ; if (value) { memcpy(modifs, var, varlen) ; modifs[varlen] = '=' ; memcpy(modifs + varlen + 1, value, modiflen - varlen - 1) ; } if (doimport) { size_t m = 0 ; char const *newargv[env_len(argv) + 6] ; newargv[m++] = EXECLINE_BINPREFIX "importas" ; newargv[m++] = "-ui" ; newargv[m++] = "--" ; newargv[m++] = var ; newargv[m++] = var ; while (*argv) newargv[m++] = *argv++ ; newargv[m++] = 0 ; xmexec0_n(newargv, value ? modifs : var, value ? modiflen : varlen + 1, 1) ; } else xmexec0_n(argv, value ? modifs : var, value ? modiflen : varlen + 1, 1) ; } execline-2.9.4.0/src/libexecline/el_modif_and_spawn.c000066400000000000000000000022261452216466500225230ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include pid_t el_modif_and_spawn (char const *const *argv, char const *var, char const *value, int doimport) { size_t varlen = strlen(var) ; size_t modiflen = value ? varlen + strlen(value) + 2 : 1 ; size_t envlen = env_len((char const *const *)environ) ; char const *newenv[envlen + 2] ; char modifs[modiflen] ; if (value) { memcpy(modifs, var, varlen) ; modifs[varlen] = '=' ; memcpy(modifs + varlen + 1, value, modiflen - varlen - 1) ; } if (!env_mergen(newenv, envlen + 2, (char const *const *)environ, envlen, value ? modifs : var, value ? modiflen : varlen + 1, 1)) return 0 ; if (doimport) { size_t m = 0 ; char const *newargv[env_len(argv) + 6] ; newargv[m++] = EXECLINE_BINPREFIX "importas" ; newargv[m++] = "-ui" ; newargv[m++] = "--" ; newargv[m++] = var ; newargv[m++] = var ; while (*argv) newargv[m++] = *argv++ ; newargv[m++] = 0 ; return el_spawn0(newargv[0], newargv, newenv) ; } else return el_spawn0(argv[0], argv, newenv) ; } execline-2.9.4.0/src/libexecline/el_parse.c000066400000000000000000000104351452216466500205060ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include int el_parse (stralloc *sa, el_chargen_func_ref next, void *source) { static unsigned char const class[256] = "`aaaaaaaaadaaaaaaaaaaaaaaaaaaaaaafcbffffffffffffjhhhhhhhiifffffffmmmmmmfffffffffffffffffffffeffffggmmmgfffffffkfffkfkfkflffnfoffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ; static uint16_t const table[17][16] = { { 0x0011, 0x0000, 0x0001, 0x2008, 0x0000, 0x0005, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2402, 0x2403 }, { 0x0011, 0x0001, 0x0001, 0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 }, { 0x0012, 0x1000, 0x0404, 0x0008, 0x1000, 0x0005, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404 }, { 0x0911, 0x0900, 0x0404, 0x0008, 0x0900, 0x0005, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404 }, { 0x0111, 0x0100, 0x0404, 0x0008, 0x0100, 0x0006, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404 }, { 0x0011, 0x2404, 0x2404, 0x2404, 0x0000, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404, 0x2404 }, { 0x0012, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404 }, { 0x0012, 0x0408, 0x0408, 0x0408, 0x0008, 0x0408, 0x0408, 0x0208, 0x448c, 0x448c, 0x0089, 0x0208, 0x0408, 0x0408, 0x0408, 0x0408 }, { 0x0012, 0x0408, 0x0408, 0x0004, 0x0408, 0x0007, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408, 0x0408 }, { 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x440a, 0x0012, 0x440a, 0x0012, 0x008e, 0x0012, 0x0012, 0x0012 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x8408, 0x040b, 0x8408, 0x040b, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x8408, 0x0410, 0x8408, 0x0410, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x8408, 0x040d, 0x040d, 0x040d, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x8408, 0x0410, 0x0410, 0x0410, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408 }, { 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x440f, 0x440f, 0x440f, 0x440f, 0x0012, 0x0012, 0x440f, 0x0012, 0x0012 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x0410, 0x0410, 0x0410, 0x0410, 0x8408, 0x8408, 0x0410, 0x8408, 0x8408 }, { 0x8111, 0x8408, 0x8408, 0x8004, 0x8408, 0x8007, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408, 0x8408 } } ; size_t mark = 0 ; unsigned int n = 0, blevel = 0 ; uint8_t state = 0, base = 10 ; while (state < 0x11) { uint16_t c ; unsigned char cur ; if (!(*next)(&cur, source)) return -1 ; c = table[state][class[cur]-'`'] ; state = c & 0x1F ; if (c & 0x8000U) { uint64_t u ; if (!stralloc_0(sa)) return -1 ; sa->len = mark ; uint64_scan_base(sa->s + sa->len, &u, base) ; if (!u || u > 0xff) return -2 ; sa->s[sa->len++] = (unsigned char)u ; } if (c & 0x4000U) mark = sa->len ; if (c & 0x2000U) { unsigned int i = blevel ; if (!stralloc_readyplus(sa, i<<2)) return -1 ; while (i--) sa->s[sa->len++] = ' ' ; } if (c & 0x1000U) sa->len -= ++blevel ; if (c & 0x0800U) { if (!blevel--) return -4 ; sa->len -= 2 ; } if (c & 0x0400U) if (!stralloc_catb(sa, (char *)&cur, 1)) return -1 ; if (c & 0x0200U) { char x = 7 + byte_chr("abtnvfr", 7, cur) ; if (!stralloc_catb(sa, &x, 1)) return -1 ; } if (c & 0x0100U) { if (n++ >= INT_MAX) return (errno = E2BIG, -1) ; if (!stralloc_0(sa)) return -1 ; } if (c & 0x0080U) { switch (cur) { case 'x' : base = 16 ; break ; case '0' : base = 8 ; break ; default : base = 10 ; } } } if (state > 0x11) return -2 ; if (blevel) return -3 ; return n ; } execline-2.9.4.0/src/libexecline/el_parse_from_buffer.c000066400000000000000000000005371452216466500230640ustar00rootroot00000000000000/* ISC license. */ #include #include #include static int next (unsigned char *c, void *p) { ssize_t r = buffer_get((buffer *)p, (char *)c, 1) ; if (r < 0) return 0 ; if (!r) *c = 0 ; return 1 ; } int el_parse_from_buffer (stralloc *sa, buffer *b) { return el_parse(sa, &next, b) ; } execline-2.9.4.0/src/libexecline/el_parse_from_string.c000066400000000000000000000004161452216466500231150ustar00rootroot00000000000000/* ISC license. */ #include #include static int next (unsigned char *c, void *p) { *c = *(*(char const **)p)++ ; return 1 ; } int el_parse_from_string (stralloc *sa, char const *s) { return el_parse(sa, &next, &s) ; } execline-2.9.4.0/src/libexecline/el_popenv.c000066400000000000000000000024371452216466500207060ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include int el_popenv (stralloc *sa, char const *const *envp, size_t envlen, char const *const *list, size_t listlen) { size_t i = 0, salen = sa->len ; int count = 0 ; for (; i < envlen ; i++) { size_t equal, colon, j = 0 ; unsigned int n ; for (; j < listlen ; j++) if (str_start(envp[i], list[j])) break ; if (j == listlen) goto copyit ; j = strlen(list[j]) ; colon = j + str_chr(envp[i] + j, ':') ; equal = j + str_chr(envp[i] + j, '=') ; if (!envp[i][equal]) goto badenv ; if (colon >= equal) { count++ ; continue ; } if (colon + 1 + uint_scan(envp[i] + colon + 1, &n) != equal) goto copyit ; if (!n) goto copyit ; if (!stralloc_catb(sa, envp[i], colon)) goto err ; if (n > 1) { char fmt[UINT_FMT+1] = ":" ; j = 1 + uint_fmt(fmt+1, n-1) ; if (!stralloc_catb(sa, fmt, j)) goto err ; } if (!stralloc_catb(sa, envp[i] + equal, strlen(envp[i] + equal) + 1)) goto err ; continue ; copyit: if (!stralloc_catb(sa, envp[i], strlen(envp[i]) + 1)) goto err ; } return count ; badenv : errno = EINVAL ; err: sa->len = salen ; return -1 ; } execline-2.9.4.0/src/libexecline/el_pushenv.c000066400000000000000000000025461452216466500210700ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include int el_pushenv (stralloc *sa, char const *const *envp, size_t envlen, char const *const *list, size_t listlen) { size_t i = 0, salen = sa->len ; int count = 0 ; for (; i < envlen ; i++) { size_t equal, colon, j = 0 ; for (; j < listlen ; j++) if (str_start(envp[i], list[j])) break ; if (j == listlen) goto copyit ; count++ ; j = strlen(list[j]) ; colon = j + str_chr(envp[i] + j, ':') ; equal = j + str_chr(envp[i] + j, '=') ; if (!envp[i][equal]) goto badenv ; if (colon >= equal) { if (!stralloc_catb(sa, envp[i], equal) || !stralloc_catb(sa, ":1", 2)) goto err ; } else { unsigned int n ; char fmt[UINT_FMT+1] = ":" ; if (colon + 1 + uint_scan(envp[i] + colon + 1, &n) != equal) goto copyit ; j = 1 + uint_fmt(fmt+1, n+1) ; if (!stralloc_catb(sa, envp[i], colon)) goto err ; if (!stralloc_catb(sa, fmt, j)) goto err ; } if (!stralloc_catb(sa, envp[i] + equal, strlen(envp[i] + equal) + 1)) goto err ; continue ; copyit: if (!stralloc_catb(sa, envp[i], strlen(envp[i]) + 1)) goto err ; } return count ; badenv : errno = EINVAL ; err: sa->len = salen ; return -1 ; } execline-2.9.4.0/src/libexecline/el_semicolon.c000066400000000000000000000017331452216466500213650ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include int el_semicolon (char const **argv) { static unsigned int nblock = 0 ; int argc1 = 0 ; nblock++ ; for (;; argc1++, argv++) { char const *arg = *argv ; if (!arg) return argc1 + 1 ; if ((arg[0] == EXECLINE_BLOCK_END_CHAR) && (!EXECLINE_BLOCK_END_CHAR || !arg[1])) return argc1 ; else if (arg[0] == EXECLINE_BLOCK_QUOTE_CHAR) ++*argv ; else { unsigned int strict = el_getstrict() ; if (strict) { char fmt1[UINT_FMT] ; char fmt2[UINT_FMT] ; fmt1[uint_fmt(fmt1, nblock)] = 0 ; fmt2[uint_fmt(fmt2, (unsigned int)argc1)] = 0 ; if (strict >= 2) strerr_dief6x(100, "unquoted argument ", arg, " at block ", fmt1, " position ", fmt2) ; else strerr_warnw6x("unquoted argument ", arg, " at block ", fmt1, " position ", fmt2) ; } } } } execline-2.9.4.0/src/libexecline/el_spawn0.c000066400000000000000000000006331452216466500206030ustar00rootroot00000000000000/* ISC license. */ #include #include #include pid_t el_spawn0 (char const *prog, char const *const *argv, char const *const *envp) { if (!argv[0]) { static char const *const newargv[3] = { EXECLINE_BINPREFIX "exit", "0", 0 } ; return cspawn(newargv[0], newargv, envp, 0, 0, 0) ; } else return cspawn(prog, argv, envp, 0, 0, 0) ; } execline-2.9.4.0/src/libexecline/el_substandrun.c000066400000000000000000000005771452216466500217520ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include "exlsn.h" void el_substandrun (int argc, char const *const *argv, char const *const *envp, exlsn_t const *info) { satmp.len = 0 ; if (!env_string(&satmp, argv, (unsigned int)argc)) strerr_diefu1sys(111, "env_string") ; el_substandrun_str(&satmp, 0, envp, info) ; } execline-2.9.4.0/src/libexecline/el_substandrun_str.c000066400000000000000000000014771452216466500226420ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include "exlsn.h" void el_substandrun_str (stralloc *src, size_t srcbase, char const *const *envp, exlsn_t const *info) { stralloc dst = STRALLOC_ZERO ; int r = el_substitute(&dst, src->s + srcbase, src->len, info->vars.s, info->values.s, genalloc_s(elsubst_t const, &info->data), genalloc_len(elsubst_t const, &info->data)) ; if (r < 0) strerr_diefu1sys(111, "el_substitute") ; if (!r) _exit(0) ; stralloc_free(src) ; { char const *v[r + 1] ; if (!env_make(v, r, dst.s, dst.len)) strerr_diefu1sys(111, "env_make") ; v[r] = 0 ; xmexec_em(v, envp, info->modifs.s, info->modifs.len) ; } } execline-2.9.4.0/src/libexecline/el_substitute.c000066400000000000000000000120601452216466500216030ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include typedef struct elsubsu_s elsubsu_t, *elsubsu_t_ref ; struct elsubsu_s { elsubst_t const *subst ; size_t pos ; } ; typedef struct subsuinfo_s subsuinfo_t, *subsuinfo_t_ref ; struct subsuinfo_s { stralloc dst ; stralloc sa ; genalloc list ; /* array of elsubsu_t */ char const *values ; } ; #define SUBSUINFO_ZERO { .dst = STRALLOC_ZERO, .sa = STRALLOC_ZERO, .list = GENALLOC_ZERO, .values = 0 } #define TEST 0x80 #define MARK 0x40 #define KEEPESC 0x20 #define INCRESC 0x10 #define STATE 0x07 #define INWORD 0x00 #define INDOLL 0x01 #define INDBR 0x02 #define INVAR 0x03 #define INVARBR 0x04 #define ACCEPT 0x05 static ssize_t parseword (stralloc *sa, genalloc *list, char const *s, char const *vars, elsubst_t const *substs, unsigned int nsubst) { static char const class[5] = "\0\\${}" ; static unsigned char const table[6][5] = { { ACCEPT, ACCEPT, ACCEPT, ACCEPT | TEST, ACCEPT }, { INWORD | KEEPESC | INCRESC, INWORD | INCRESC, INWORD | INCRESC, INWORD | TEST | INCRESC, INWORD | INCRESC }, { INDOLL | KEEPESC, INDOLL, INDOLL, INDOLL | TEST, INDOLL }, { INWORD, INDBR | KEEPESC, INWORD, INWORD | TEST, INWORD }, { INWORD, INWORD, INWORD, INWORD | TEST, INWORD | TEST }, { INWORD, INVAR | MARK | KEEPESC, INVARBR | MARK | KEEPESC, INVAR | KEEPESC, INVARBR | KEEPESC } } ; size_t mark = 0, offset = 0, esc = 0, salen = sa->len, listlen = genalloc_len(elsubsu_t, list) ; ssize_t pos = 0 ; unsigned char state = INWORD ; while (state != ACCEPT) { int nopush = 0 ; unsigned char c = table[byte_chr(class, 5, s[pos])][state] ; if (c & TEST) { unsigned int supp = (state == INVARBR) ; unsigned int i = 0 ; for (; i < nsubst ; i++) { if (!strncmp(vars + substs[i].var, s + mark, pos - mark) && !vars[substs[i].var + pos - mark]) { sa->len -= esc >> 1 ; offset += esc >> 1 ; if (esc & 1) { memmove(sa->s + mark - offset - 2 - supp, sa->s + mark - offset + (esc>>1) - 1 - supp, pos - mark + 1 + supp) ; sa->len-- ; offset++ ; } else { elsubsu_t cur ; cur.subst = substs + i ; cur.pos = mark - offset - 1 - supp ; if (!genalloc_append(elsubsu_t, list, &cur)) goto err ; offset += sa->len - cur.pos ; sa->len = cur.pos ; if (supp) nopush = 1 ; } break ; } } } if (nopush) offset++ ; else if (!stralloc_catb(sa, s+pos, 1)) goto err ; if (c & MARK) mark = pos ; if (!(c & KEEPESC)) esc = 0 ; if (c & INCRESC) esc++ ; state = c & STATE ; pos++ ; } sa->len-- ; return pos ; err: sa->len = salen ; list->len = listlen ; return -1 ; } static int substword (subsuinfo_t *info, size_t wordstart, size_t wordlen, unsigned int n, size_t offset) { if (n < genalloc_len(elsubsu_t, &info->list)) { elsubsu_t *list = genalloc_s(elsubsu_t, &info->list) ; char const *p = info->values + list[n].subst->value ; size_t l = list[n].pos + offset ; size_t dstbase = info->dst.len ; size_t sabase = info->sa.len ; unsigned int i = 0 ; int nc = 0 ; if (!stralloc_readyplus(&info->sa, l)) return -1 ; stralloc_catb(&info->sa, info->sa.s + wordstart, l) ; for (; i < list[n].subst->n ; i++) { size_t plen = strlen(p) ; int r ; info->sa.len = sabase + l ; if (!stralloc_readyplus(&info->sa, plen + wordlen - l)) goto err ; stralloc_catb(&info->sa, p, plen) ; stralloc_catb(&info->sa, info->sa.s + wordstart + l, wordlen - l) ; r = substword(info, sabase, info->sa.len - sabase, n+1, offset + plen) ; if (r < 0) goto err ; nc += r ; p += plen+1 ; } return nc ; err: info->sa.len = sabase ; info->dst.len = dstbase ; return -1 ; } else { if (!stralloc_readyplus(&info->dst, wordlen+1)) return -1 ; stralloc_catb(&info->dst, info->sa.s + wordstart, wordlen) ; stralloc_0(&info->dst) ; return 1 ; } } int el_substitute (stralloc *dst, char const *src, size_t len, char const *vars, char const *values, elsubst_t const *substs, unsigned int nsubst) { subsuinfo_t info = SUBSUINFO_ZERO ; size_t i = 0 ; int nc = 0 ; int wasnull = !dst->s ; if (!stralloc_copy(&info.dst, dst)) return -1 ; info.values = values ; while (i < len) { genalloc_setlen(elsubsu_t, &info.list, 0) ; info.sa.len = 0 ; { ssize_t r = parseword(&info.sa, &info.list, src + i, vars, substs, nsubst) ; if (r < 0) goto err ; i += r ; } { int r = substword(&info, 0, info.sa.len, 0, 0) ; if (r < 0) goto err ; nc += r ; } } genalloc_free(elsubsu_t, &info.list) ; stralloc_free(&info.sa) ; if (!wasnull) stralloc_free(dst) ; *dst = info.dst ; return nc ; err : genalloc_free(elsubsu_t, &info.list) ; stralloc_free(&info.sa) ; stralloc_free(&info.dst) ; return -1 ; } execline-2.9.4.0/src/libexecline/el_transform.c000066400000000000000000000034651452216466500214140ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include static void el_crunch (stralloc *sa, size_t base, char const *delim) { size_t i = base, j = base ; int crunching = 0 ; for (; i < sa->len ; i++) { if (!crunching) sa->s[j++] = sa->s[i] ; if (strchr(delim, sa->s[i])) crunching = 1 ; else if (crunching) { i-- ; crunching = 0 ; } } sa->len = j ; } static int el_split (stralloc *sa, size_t base, eltransforminfo_t const *si, int chomped) { int n = 0 ; size_t i = base ; for (; i < sa->len ; i++) if (strchr(si->delim, sa->s[i])) { sa->s[i] = 0 ; n++ ; base = i+1 ; } if (sa->len && sa->s[sa->len - 1]) { if (si->chomp && !chomped) sa->len = base ; else if (!stralloc_0(sa)) return -1 ; else n++ ; } return n ; } static int el_splitnetstring (stralloc *sa, size_t base) { size_t tmpbase = satmp.len, i = base ; int n = 0 ; while (i < sa->len) { ssize_t r = netstring_decode(&satmp, sa->s + i, sa->len - i) ; if (r < 0) goto err ; if (!stralloc_0(&satmp)) goto err ; i += r ; n++ ; } sa->len = base ; if (!stralloc_catb(sa, satmp.s + tmpbase, satmp.len - tmpbase)) { sa->len = i ; goto err ; } satmp.len = tmpbase ; return n ; err: satmp.len = tmpbase ; return -1 ; } int el_transform (stralloc *sa, size_t i, eltransforminfo_t const *si) { int chomped = 0 ; if (si->crunch && *si->delim) el_crunch(sa, i, si->delim) ; if (si->chomp && (sa->len > i) && strchr(si->delim, sa->s[sa->len-1])) { sa->len-- ; chomped = 1 ; } return si->split ? *si->delim ? el_split(sa, i, si, chomped) : el_splitnetstring(sa, i) : stralloc_0(sa) ? 1 : -1 ; } execline-2.9.4.0/src/libexecline/el_vardupl.c000066400000000000000000000003711452216466500210470ustar00rootroot00000000000000/* ISC license. */ #include #include int el_vardupl (char const *key, char const *s, size_t len) { size_t i = 0 ; for (; i < len ; i += strlen(s + i) + 1) if (!strcmp(key, s + i)) return 1 ; return 0 ; } execline-2.9.4.0/src/libexecline/exlp.c000066400000000000000000000046031452216466500176640ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include "exlsn.h" int exlp (unsigned int nmin, char const *const *envp, exlsn_t *info) { size_t varbase = info->vars.len ; size_t valbase = info->values.len ; size_t datbase = genalloc_len(elsubst_t, &info->data) ; size_t poszero ; elsubst_t blah ; char const *x = env_get2(envp, "#") ; unsigned int n, ntot, i = 0 ; if (!x) return -2 ; if (!uint0_scan(x, &n)) return -2 ; if (el_vardupl("#", info->vars.s, info->vars.len)) return -2 ; if (el_vardupl("@", info->vars.s, info->vars.len)) return -2 ; { unsigned int strict = el_getstrict() ; if (strict && (n < nmin)) { char fmta[UINT_FMT] ; char fmtn[UINT_FMT] ; fmta[uint_fmt(fmta, n)] = 0 ; fmtn[uint_fmt(fmtn, nmin)] = 0 ; if (strict > 1) strerr_dief4x(100, "too few arguments: expected at least ", fmtn, " but got ", fmta) ; else strerr_warnw4x("too few arguments: expected at least ", fmtn, " but got ", fmta) ; } } blah.var = varbase ; blah.value = info->values.len ; blah.n = 1 ; if (!stralloc_catb(&info->vars, "#\0@", 4) || !stralloc_catb(&info->values, x, strlen(x) + 1) || !genalloc_append(elsubst_t, &info->data, &blah)) goto err ; ntot = n > nmin ? n : nmin ; poszero = info->values.len ; for (; i <= ntot ; i++) { char fmt[UINT_FMT] ; size_t l = uint_fmt(fmt, i) ; fmt[l] = 0 ; if (el_vardupl(fmt, info->vars.s, info->vars.len)) goto err2 ; x = (i <= n) ? env_get2(envp, fmt) : "" ; if (!x) goto err2 ; blah.var = info->vars.len ; blah.value = info->values.len ; blah.n = 1 ; if (!stralloc_catb(&info->vars, fmt, l+1) || !stralloc_catb(&info->values, x, strlen(x) + 1) || !genalloc_append(elsubst_t, &info->data, &blah)) goto err ; } blah.var = varbase + 2 ; blah.value = poszero + strlen(info->values.s + poszero) + 1 ; blah.n = n ; if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; return n ; err: info->vars.len = varbase ; info->values.len = valbase ; genalloc_setlen(elsubst_t, &info->data, datbase) ; return -1 ; err2: info->vars.len = varbase ; info->values.len = valbase ; genalloc_setlen(elsubst_t, &info->data, datbase) ; return -2 ; } execline-2.9.4.0/src/libexecline/exlsn_define.c000066400000000000000000000026601452216466500213600ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include "exlsn.h" int exlsn_define (int argc, char const **argv, char const *const *envp, exlsn_t *info) { eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; subgetopt localopt = SUBGETOPT_ZERO ; elsubst_t blah ; blah.var = info->vars.len ; blah.value = info->values.len ; for (;;) { int opt = subgetopt_r(argc, argv, "NnsCcd:", &localopt) ; if (opt < 0) break ; switch (opt) { case 'N' : si.chomp = 0 ; break ; case 'n' : si.chomp = 1 ; break ; case 's' : si.split = 1 ; break ; case 'C' : si.crunch = 1 ; break ; case 'c' : si.crunch = 0 ; break ; case 'd' : si.delim = localopt.arg ; break ; default : return -3 ; } } argc -= localopt.ind ; argv += localopt.ind ; if (argc < 2) return -3 ; if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; if (!stralloc_catb(&info->vars, argv[0], strlen(argv[0]) + 1)) return -1 ; if (!stralloc_cats(&info->values, argv[1])) goto err ; { int r = el_transform(&info->values, blah.value, &si) ; if (r < 0) goto err ; blah.n = r ; } if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; (void)envp ; return localopt.ind + 2 ; err: info->vars.len = blah.var ; info->values.len = blah.value ; return -1 ; } execline-2.9.4.0/src/libexecline/exlsn_elglob.c000066400000000000000000000040141452216466500213650ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include #include "exlsn.h" static int elgloberrfunc (char const *s, int e) { errno = e ; strerr_warnw2sys("while globbing, error reading ", s) ; return 0 ; } int exlsn_elglob (int argc, char const **argv, char const *const *envp, exlsn_t *info) { glob_t pglob ; subgetopt localopt = SUBGETOPT_ZERO ; elsubst_t blah ; int flags = GLOB_NOSORT | GLOB_NOCHECK ; unsigned int i = 0 ; int verbose = 0 ; blah.var = info->vars.len ; blah.value = info->values.len ; for (;;) { int opt = subgetopt_r(argc, argv, "vwsme0", &localopt) ; if (opt < 0) break ; switch (opt) { case 'v' : verbose = 1 ; break ; case 'w' : flags |= GLOB_ERR ; break ; case 's' : flags &= ~GLOB_NOSORT ; break ; case 'm' : flags |= GLOB_MARK ; break ; case 'e' : flags |= GLOB_NOESCAPE ; break ; case '0' : flags &= ~GLOB_NOCHECK ; break ; default : return -3 ; } } argc -= localopt.ind ; argv += localopt.ind ; if (argc < 2) return -3 ; if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; if (!stralloc_catb(&info->vars, argv[0], strlen(argv[0]) + 1)) return -1 ; pglob.gl_offs = 0 ; switch (glob(argv[1], flags, verbose ? &elgloberrfunc : 0, &pglob)) { case 0 : break ; case GLOB_NOMATCH: { pglob.gl_pathc = 0 ; pglob.gl_pathv = 0 ; break ; } default: goto err ; } for ( ; i < (unsigned int)pglob.gl_pathc ; i++) if (!stralloc_catb(&info->values, pglob.gl_pathv[i], strlen(pglob.gl_pathv[i]) + 1)) goto globerr ; blah.n = pglob.gl_pathc ; globfree(&pglob) ; if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; (void)envp ; return localopt.ind + 2 ; globerr: globfree(&pglob) ; err: info->vars.len = blah.var ; info->values.len = blah.value ; return -1 ; } execline-2.9.4.0/src/libexecline/exlsn_exlp.c000066400000000000000000000011401452216466500210660ustar00rootroot00000000000000/* ISC license. */ #include #include #include "exlsn.h" int exlsn_exlp (int argc, char const **argv, char const *const *envp, exlsn_t *info) { subgetopt localopt = SUBGETOPT_ZERO ; unsigned int nmin = 0 ; int n ; for (;;) { int opt = subgetopt_r(argc, argv, "P:", &localopt) ; if (opt < 0) break ; switch (opt) { case 'P' : if (uint0_scan(localopt.arg, &nmin)) break ; default : return -3 ; } } argc -= localopt.ind ; argv += localopt.ind ; n = exlp(nmin, envp, info) ; if (n < 0) return n ; return localopt.ind ; } execline-2.9.4.0/src/libexecline/exlsn_free.c000066400000000000000000000003531452216466500210440ustar00rootroot00000000000000/* ISC license. */ #include #include "exlsn.h" void exlsn_free (exlsn_t *info) { stralloc_free(&info->vars) ; stralloc_free(&info->values) ; stralloc_free(&info->data) ; stralloc_free(&info->modifs) ; } execline-2.9.4.0/src/libexecline/exlsn_importas.c000066400000000000000000000037151452216466500217660ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include #include #include "exlsn.h" int exlsn_importas (int argc, char const **argv, char const *const *envp, exlsn_t *info) { eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; subgetopt localopt = SUBGETOPT_ZERO ; elsubst_t blah ; char const *defaultval = 0 ; char const *x ; int insist = 0 ; int unexport = 0 ; blah.var = info->vars.len ; blah.value = info->values.len ; for (;;) { int opt = subgetopt_r(argc, argv, "iuD:NnsCcd:", &localopt) ; if (opt < 0) break ; switch (opt) { case 'i' : insist = 1 ; break ; case 'u' : unexport = 1 ; break ; case 'D' : defaultval = localopt.arg ; break ; case 'N' : si.chomp = 0 ; break ; case 'n' : si.chomp = 1 ; break ; case 's' : si.split = 1 ; break ; case 'C' : si.crunch = 1 ; break ; case 'c' : si.crunch = 0 ; break ; case 'd' : si.delim = localopt.arg ; break ; default : return -3 ; } } argc -= localopt.ind ; argv += localopt.ind ; if ((unsigned int)argc < 2) return -3 ; if (!*argv[0] || el_vardupl(argv[0], info->vars.s, info->vars.len)) return -2 ; if (!stralloc_catb(&info->vars, argv[0], strlen(argv[0]) + 1)) return -1 ; x = env_get2(envp, argv[1]) ; if (!x) { if (insist) strerr_dienotset(100, argv[1]) ; x = defaultval ; } else if (unexport) { if (!stralloc_catb(&info->modifs, argv[1], strlen(argv[1]) + 1)) goto err ; } if (!x) blah.n = 0 ; else { int r ; if (!stralloc_cats(&info->values, x)) goto err ; r = el_transform(&info->values, blah.value, &si) ; if (r < 0) goto err ; blah.n = r ; } if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; return localopt.ind + 2 ; err: info->vars.len = blah.var ; info->values.len = blah.value ; return -1 ; } execline-2.9.4.0/src/libexecline/exlsn_main.c000066400000000000000000000013241452216466500210460ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include "exlsn.h" void exlsn_main (int argc, char const **argv, char const *const *envp, exls_func *func, char const *usage) { exlsn_t info = EXLSN_ZERO ; int r = (*func)(argc, argv, envp, &info) ; if (r < 0) switch (r) { case -4 : strerr_dief1x(100, "empty block") ; case -3 : strerr_dieusage(100, usage) ; case -2 : strerr_dief1x(111, "bad substitution key") ; case -1 : strerr_diefu1sys(111, "complete exlsn function") ; default : strerr_diefu2x(111, "complete exlsn function", ": unknown error") ; } el_substandrun(argc-r, argv+r, envp, &info) ; } execline-2.9.4.0/src/libexecline/exlsn_multidefine.c000066400000000000000000000044011452216466500224260ustar00rootroot00000000000000/* ISC license. */ #include #include #include #include #include #include "exlsn.h" int exlsn_multidefine (int argc, char const **argv, char const *const *envp, exlsn_t *info) { eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; subgetopt localopt = SUBGETOPT_ZERO ; size_t varbase = info->vars.len ; size_t valbase = info->values.len ; size_t pos = valbase ; unsigned int i = 0 ; unsigned int max ; char const *x ; int argc1 ; int zeroword = 0, likeread = 0 ; si.split = 1 ; for (;;) { int opt = subgetopt_r(argc, argv, "0rNnCcd:", &localopt) ; if (opt < 0) break ; switch (opt) { case '0' : zeroword = 1 ; break ; case 'r' : likeread = 1 ; break ; case 'N' : si.chomp = 0 ; break ; case 'n' : si.chomp = 1 ; break ; case 'C' : si.crunch = 1 ; break ; case 'c' : si.crunch = 0 ; break ; case 'd' : si.delim = localopt.arg ; break ; default : return -3 ; } } argc -= localopt.ind ; argv += localopt.ind ; if (argc < 2) return -3 ; x = argv[0] ; argv++ ; argc-- ; argc1 = el_semicolon(argv) ; if (!argc1) return -4 ; if (argc1 >= argc) return -3 ; if (!stralloc_cats(&info->values, x)) return -1 ; { int r = el_transform(&info->values, valbase, &si) ; if (r < 0) goto err ; max = r ; } if (!stralloc_0(&info->values)) goto err ; for (; i < (unsigned int)argc1 ; i++) { if (*argv[i]) { elsubst_t blah ; blah.var = info->vars.len ; if (el_vardupl(argv[i], info->vars.s, info->vars.len)) goto err2 ; if (!stralloc_catb(&info->vars, argv[i], strlen(argv[i]) + 1)) goto err ; blah.value = i < max ? pos : info->values.len - 1 ; blah.n = (i < max) || !zeroword ; if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; } if (i < max) pos += strlen(info->values.s + pos) + 1 ; } if ((i < max) && likeread) genalloc_s(elsubst_t, &info->data)[genalloc_len(elsubst_t, &info->data) - 1].n = max - i + 1 ; (void)envp ; return localopt.ind + argc1 + 2 ; err: info->vars.len = varbase ; info->values.len = valbase ; return -1 ; err2: info->vars.len = varbase ; info->values.len = valbase ; return -2 ; } execline-2.9.4.0/src/multicall/000077500000000000000000000000001452216466500162505ustar00rootroot00000000000000execline-2.9.4.0/src/multicall/deps-exe/000077500000000000000000000000001452216466500177625ustar00rootroot00000000000000execline-2.9.4.0/src/multicall/deps-exe/execline000066400000000000000000000001051452216466500214750ustar00rootroot00000000000000${LIBEXECLINE} ${LIBNSSS} -lskarnet ${SPAWN_LIB} ${MAYBEPTHREAD_LIB} execline-2.9.4.0/tools/000077500000000000000000000000001452216466500146335ustar00rootroot00000000000000execline-2.9.4.0/tools/gen-deps.sh000077500000000000000000000052641452216466500167030ustar00rootroot00000000000000#!/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" execline-2.9.4.0/tools/gen-multicall.sh000077500000000000000000000054431452216466500177350ustar00rootroot00000000000000#!/bin/sh -e LC_ALL=C ; export LC_ALL echo '/* ISC license. */' echo echo '#include ' echo '#include ' echo { echo '#include ' ; echo '#include ' ; cat src/execline/*.c | grep '^#include <' | grep -vF ' #include #include #include #include "exlsn.h" #include typedef int main_func (int, char **, char const *const *) ; typedef main_func *main_func_ref ; typedef struct execline_app_s execline_app, *execline_app_ref ; struct execline_app_s { char const *name ; main_func_ref mainf ; } ; static int execline_app_cmp (void const *a, void const *b) { char const *name = a ; execline_app const *p = b ; return strcmp(name, p->name) ; } EOF for i in `ls -1 src/execline/deps-exe` ; do j=`echo $i | tr - _` echo grep -v '^#include ' < src/execline/${i}.c | grep -vF '/* ISC license. */' | sed -e "s/int main (int argc, char \(.*\)\*argv.*$/int ${j}_main (int argc, char \1*argv, char const *const *envp)/" echo echo '#undef USAGE' echo '#undef dieusage' echo '#undef dienomem' done cat <mainf))(argc-1, argv+1, envp) ; } int main (int argc, char **argv, char const *const *envp) { execline_app const *p ; char const *name = strrchr(argv[0], '/') ; if (name) name++ ; else name = argv[0] ; p = bsearch(name, execline_apps, sizeof(execline_apps) / sizeof(execline_app), sizeof(execline_app), &execline_app_cmp) ; return p ? (*(p->mainf))(argc, argv, envp) : execline_main(argc, argv, envp) ; } EOF execline-2.9.4.0/tools/install.sh000077500000000000000000000020551452216466500166420ustar00rootroot00000000000000#!/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