Go to the previous, next section.
The shell is the system's user interface, it is a very simple command line based shell. The set of commands recognised by the shell's parser is dynamically extendable: other parts of the system are able to register commands they have implemented with the shell.
The shell is stored in the module `shell', all functions and variables documented in this chapter are found in this module. The module structure is defined in the shell's header file: `<vmm/shell.h>'.
Each shell uses a tty to give it a virtual display and a logical
keyboard (see section TTY Driver). The shell created when the system is
initialised is called the system shell, all output from the
kernel's printf
functions is written to the display of this
shell. The hot key Alt-SysReq can be used to switch to
this display.
The shell reads its input one line at a time, either from its tty or the file being executed if the shell is currently parsing a shell script. Once a whole line has been read it is split into words, each of which is separated by a sequence of white space characters (either spaces or tabs). To create a word which contains spaces it can be bracketed by two single-quote (`'') characters. If the first non-white space character in a line is a hash character (`#') the line is treated as a comment and ignored.
After tokenising its input line the shell uses the first word in the line to identify the command being invoked. It uses this word to search the hash table of available commands, if one matches the function associated with this command is called with the remaining words in the command line as its parameters.
Shell scripts are files containing shell command lines, the
source
shell command is used to execute a named shell script.
The commands in a shell script are executed in order just as though
they had been typed at a tty (except no prompt string is printed).
The system is not restricted to only one shell; the shell
shell
command and the hot key Alt-ESC both create a new shell
process, running in a new tty.
To help the user of the system the shell and its commands provide a
simple online help system. When each command is registered a short
string documenting the command must be provided along with the pointer
to the function implementing the command. The help
shell
command then uses these strings to provide short pieces of help
information.
Shell Command: help [command-name]
This command implements the shell's online help system. Invoking the command with no parameter prints a list of the available commands to the shell's display.
When given the command-name parameter names a command, its documentation string is searched for and if it exists it will be printed to the display.
Each shell command is implemented by a C function. When the command is invoked its function is called with three arguments, a structure defining which shell the command was invoked by, the number of parameters to the command and an array of string pointers defining the arguments themselves. The function should return an integer defining the result of the command: zero for success, various non-zero values for different types of errors. The shell structure looks like this:
struct shell { /* The task the shell is running on. */ struct task *task; /* The shell's tty device. */ struct tty *tty; /* If non-null a shell script is being executed from this file. */ struct file *src; /* A pointer to the shell module, this saves commands opening the shell explicitly. */ struct shell_module *shell; /* The result of the last command executed. */ int last_rc; /* The current prompt. */ #define PROMPT_SIZE 40 char prompt[PROMPT_SIZE]; };
shell Function: void add_command (const char *name, int (*func)(struct shell *sh, int argc, char **argv), const char *doc)
This function adds the command named name, implemented by the function func and with documentation string doc, to the shell's hash table of available commands.
The function func is called with the shell structure, the number of arguments and an array of arguments. It should return an integer defining its result, zero means success. Predefined result values are:
RC_OK
RC_WARN
RC_FAIL
RC_QUIT_NOW
The following example function could be used to implement a shell command:
int cmd_foo(struct shell *sh, int argc, char **argv) { if(argc == 0) { sh->shell->printf(sh, "error: no argument\n"); return RC_WARN; } sh->shell->printf(sh, "first arg: %s\n", argv[0]); return RC_OK; }
shell Function: bool remove_command (const char *name)
Removes the command called name from the hash table of commands.
If no such command exists FALSE
is returned, otherwise
TRUE
.
Many modules implement more than one shell command, to save having to
call add_command
more than once special functions are provided
to add a list of commands in one go. Each list of shell commands is
stored in a special structure:
struct shell_cmds { /* Used by the kernel shell functions. */ struct shell_cmds *next; /* An array defining the commands to add. */ struct { const char *name; int (*func)(struct shell *, int, char **); const char *doc; } cmds[0]; };
The last entry in the array should be three zeros to act as a
sentinel, the macro END_CMD
can be used to define such an entry.
Another useful macro is CMD
, this expands to an entry in an
array of commands from its single argument defining the name of the
command. It depends on the command's function being the string
`cmd_' followed by the name of the command, and the command's
documentation being a macro called `DOC_' followed by the name of
the command. So an example list of commands could be:
struct shell_cmds shell_cmds = { 0, { CMD(echo), CMD(prompt), CMD(help), CMD(quit), CMD(cls), CMD(shell), CMD(source), CMD(ed), END_CMD } };
shell Function: void add_cmd_list (struct shell_cmds *cmds)
Add the shell commands defined by the list cmds to the shell.
Note that it's usually easier to call the function add_shell_cmds
defined by the kernel. See section Adding Commands With The Kernel.
shell Function: void remove_cmd_list (struct shell_cmds *cmds)
Remove each command in the list of commands cmds from the shell.
Due to the modular design of the system, each module that implements shell commands usually registers them when the module is initialised. This can cause problems: some modules are loaded before the shell --- therefore there's no way for them to add their commands.
To solve this problem we decided to implement a delayed-registration function. This is part of the kernel, when called with a list of shell commands it guarantees to register them with the system's shell module. If the shell hasn't yet been loaded the commands are simply added to the list of commands waiting to be registered, otherwise they are immediately added to the shell. When the shell is loaded it calls a kernel function to collect the commands waiting to be registered.
Another advantage of this method is that module's implementing shell commands don't even need to open the shell module: they use the kernel to add their commands. When one of their commands is invoked it can use the pointer to the shell module stored in the shell structure.
All functions defined in this section are part of the kernel module. See section The Kernel.
kernel Function: void add_shell_cmds (struct shell_cmds *cmds)
Add the list of shell commands cmds to the shell as soon as is possible. This is the recommended method of adding commands to the shell.
Note that the only possible way to remove commands added to the shell
by this function is with the remove_shell_cmds
function
described below.
kernel Function: void remove_shell_cmds (struct shell_cmds *cmds)
Remove the list of shell commands added to the shell by the
add_shell_cmds
function.
kernel Function: void collect_shell_cmds (void)
This function should be called by the shell after it has initialised
itself. Each list of commands waiting to be installed into the shell
(from the add_shell_cmds
function) is applied to the shell
module's add_cmd_list
function.
shell Function: void print (struct shell *sh, const char *text, size_t length)
Print length characters of the string text to the tty of the shell represented by the structure sh.
shell Function: void printf (struct shell *sh, const char *fmt, ...)
Print a formatted string to the tty of the shell sh. This string is formatted by the kernel function vsprintf using the fmt parameter and any other parameters given to this function.
shell Function: void perror (struct shell *sh, const char *msg)
This function prints an error message to the tty of the shell sh.
If the msg parameter is not a null pointer the string that it
points to is printed, followed by a colon and text describing the
contents of the current task's errno
field. If msg is a
null pointer only the message describing errno
is printed.
See section Error Codes.
Go to the previous, next section.