execline

AMG: execline [L1 ] is a non-interactive scripting language. It is designed to be secure and embeddable. The execline and execlineb languages are extremely minimal, and all runtime functionality is provided by external programs.

One highly unusual yet important aspect of execline is that while the script is running, the interpreter is not resident. In a manner of speaking, the script runs itself! This is accomplished through massive amounts of Bernstein chaining: every program does its thing then execs into the next program. Each program receives its continuation as an argument. In the case of if and similar, there are several possible continuations, all passed as arguments.

execline comes with a suite of commands for providing the basics. See the execline page for the full list and links to manuals. It is important to note that some of the section headings on the execline page are themselves links.


To show a little bit about how this language works, here's my /service/clockspeed_adjust/run script. This script periodically gets the time from an NTP server so that clockspeed [L2 ] can gauge the actual speed of the hardware clock.

#!/command/execlineb

# Redirect stderr to stdout.
fdmove -c 2 1

# Switch to clockspeed_adjust's UID and GID.
envuidgid Gclockspeed_adjust

# Limit the the size of the data segment.
softlimit -d 131072

# Get the IP address of the NTP server.
backtick -n SERVER { head -1 cfg/SERVER }

# Loop forever.
loopwhile {
    # Obtain timing mark for calibrating clockspeed adjustment.
    foreground { echo "Obtaining new calibration mark from ${SERVER}:" }
    foreground {
        pipeline { sntpclock ${SERVER} }
        pipeline { tee /package/misc/spf/clockspeed/adjust }
                   clockview
    }

    # Read the current "attoseconds" value into the log.
    foreground { echo "Viewing current attoseconds in hardware tick:" }
    foreground {
        redirfd -r 0 /package/misc/spf/clockspeed/etc/atto
        clockview
    }

    # Grab the current values of WAIT and WAIT_MAX.
    multisubstitute {
        backtick -n WAIT     { head -1 cfg/WAIT     }
        backtick -n WAIT_MAX { head -1 cfg/WAIT_MAX }
    }

    # Wait.
    foreground { echo "Waiting ${WAIT} seconds until next adjustment..." }
    foreground { sleep ${WAIT} }

    # Compute the new value for $WAIT.
    backtick -n WAIT_NEW { expr ${WAIT} * 3 }
    redirfd -w 1 cfg/WAIT
    ifthenelse { test ${WAIT_NEW} -lt ${WAIT_MAX} }
        { echo ${WAIT_NEW} } { echo ${WAIT_MAX} }
}

# vim: set ts=4 sts=4 sw=4 tw=80 et:

execlineb reads in this script, strips comments, converts the brace notation to the tilde notation used by execline and friends, then execs into the resulting "script". In this case that means running fdmove -c 2 1 envuidgid Gclockspeed_adjust softlimit -d 131072 backtick -n SERVER ~head ~-1 ~cfg/SERVER ; loopwhile .... If you want to see the full shebang, get execline, put the above script in a file, add echo as the first command, then run it. (Do it! This will give you an important insight into how execline really works.)

Anyway, fdmove starts, redirects its stderr to its stdout, then execs into envuidgid. And so on. backtick forks and execs into head, collects its stdout, substitutes it for every occurrence of ${SERVER} in the remainder of its argv, and execs into loopwhile with the modified argv. loopwhile repeatedly fork/execs into its "first" argument (everything up until the ; which corresponds to the closing brace). I think you get the picture.

Even though there's no resident interpreter, the above script manages to maintain state. It does so through the filesystem. At the end of the loop, it computes a value and writes it into the file cfg/WAIT. At the beginning of the loop, it reads a value from cfg/WAIT and substitutes it for ${WAIT}.

Kinda neat, I think. A language simpler than lisp, hehehe.