The Spin Shell

The spinshell is a minimal shell that just raises the event Run. All commands are defined as event handlers for SpinShell.Run. All commands are defined either in shell/Commands or in an extension.

The shell supports variable substitution and some rudimentary syntax for simplifying your life. It also defines a few initial shell variables based on the build configuration that you can use to help simplify your life.

Commands

The shell directory is split into several component subdirectories, each of which exports a separate interface and domain. There's no fundamental reason for this other than to provide a simple (and used) example of how to partition a bunch of code.

The different packages are:

shellcore
Basic parsing services and Shell.i3 interface.
consoleshell
Driver started up at boottime to attach the shell services to the console.
basiccmds
A collection of useful primitive commands. Most of what you need goes here.
utils
some additional "utility" programs that are not big enough to stand on their own elsewhere so they get thrown into the shell.
expr
Commands that treat other shell commands as expressions.
regress
Regression tests.

Using the Shell

To use the shell, type at it. The shell is a statically linked system extension. That is, no kernel services rely on it, but it's hard to get much done without it.

Shell commands are expected to adhere to a UNIX-like invocation syntax:

command -flag1 -flag2 argument -flag3 argument  
Specifically, flags are prefixed with a "-" and arguments are just given as they are.

IMPORTANT: Not all shell commands are so adhering. We'll fix this over the next few releases.

Shell Variables

The shell allows you to set and access shell variables. Useful commands provided here are:
set var value
sets the variable var to the value value.
"set" by itself just dumps all the shell variables.
$var
expands var to the last set value.
Variable expansion is done before commands are passed through to their handlers. So, you can even create aliases for commands that you don't like to type.
echo $var
shows the value of $var.

Variable expansion works

Variable expansion is not as powerful in real shells, but it does work ok. Supports $x is "foo", then Some things you can't do. For example, if you have $x and $xy, then there is no way to refer to $x in the string $xy (eg, you can't currently do ${x}y.) If this is annoying enough, we can fix it.

Some builtin shell variables

On system boot, the shell defines a few builtin shell values that are of general use. If you don't like their values, you are free to change them with "set."
$user
sets to the name of the person who built the system. eg "bershad".
$home
set to the root of the source tree from which the kernel was built, eg, "/spin/bershad."
This is a funny kind of root, since it is assumed to be valid in the TFTP file namespace, which is a bit wierd. Basically, the root of our tftp space is /afs/cs/project, so if your home is /spin/camcam, that would correspond to /afs/cs/project/spin/camcam
~ (that's right, TILDE)
equivalent to $home, eg, ~/spin/spindle/version/version.config would name the config file /afs/cs/project/spin/bershad/spin/spindle/version/version.config.
$version
expands to the version string embedded in the kernel. Useful for figuring out what version of the system you are looking at.
$builddir
expands to where the kernel thinks it got stored during build. For example, my $builddir usually expands to /afs/cs/project/spin/bershad/spin/sal/SPIN. Useful for making sure you're looking at the kernel you think you're looking at.

Builtin, or nearly builtin shell commands

Minimally, the shell supports only a few builtin operations:
load -conf -trust file
Load the named file as an extension. If -conf is specified, the file is assumed to be a configuration file that contains object files which should be loaded and linked into a single domain. If -trust is specified, the file is loaded into a trusted domain.
script -i file
source the named file as though the commands had been typed in from the shell. The special "-i" flag can be used without a filename to read in the script /spin/$user/spin/scripts/$user.spininit, where $user is whoever built the kernel.
script -b
runs /spin/$user/scpin/scripts/boot.rc
help
Lists all shell commands.

Shell commands that are extensions

Most shell commands are dynamically linked into the system once the system boots. Type "help" from the spinshell prompt to discover what these are.

Writing new Shell Commands

It's so very easy to write a new shell command. You need only three things:

The basic idea is to create an interface for your command, define the command name and help string in the interface, and also define the entry function. Shazam. You feed this interface (and its implementation) to a template (command.tmpl from the sys/src/shell/Commands) directory and everything else is taken care of for you. Here's an example which defines the kernel's "date" command:

src/Date.i3
The interface
src/Date.m3
The implementation
src/m3makefile
The m3makefile.
It works like magic. When you build this stuff, you'll get four files that must be downloaded to implement your command:
DateCmd.io, DateCmd.mo
The interface and implementation files for the generic instantiation of your command.
Date.io, Date.mo
Your interface and implementation files.
If you are building a config file, you should specify the order as DateCmd.io, DateCmd.mo, Date.io, Date.mo.

How does it work?

Your command module is providing an implementation for the generic Command module. Three files are involved:
Command.mg.
Generic implementation.
Command.ig.
Generic interface.
command.tmpl.
The quake directives that instantiate your generic from the CommandModule directive.

Generics make it all easy

This generic takes your "Run" command and installs it as a handler on the SpinShell's exported Run event. It also creates and installs a "Help" handler for the SpinShell.


bershad@cs.washington.edu
Last modified June 10, 1996