aldos operator's manual

ortfero

introduction

aldos is the operating system of the aldan machine. it is intended for single-seat operation: one installation, served by one operator, with a single console as the only point of interaction.

this manual is addressed to the operator. the role is to be distinguished from that of the user. a user invokes a program and, when the program has completed, has no further duty toward the system. the operator is permanently responsible for the condition of the machine. the operator determines which programs are present on the disk, which libraries are made available at boot, and the state in which the system is left between sessions. when the disk fills, the operator reclaims it. when a program fails to load, the operator identifies the cause.

aldos provides no facility for remote administration. no other party may be called upon to maintain, repair, or audit the installation. every byte stored on the disk is the consequence of an action taken by the operator or of the execution of a program selected by the operator. the operator is expected to acknowledge this condition before assuming the role.

the operator is accountable for every byte on the disk.

how the system works

aldos is built from a small number of moving parts. the operator should learn each before the prompt is useful.

the kernel is the part of the system that is always running. it schedules tasks, carries messages between them, and owns the machine's hardware. nothing else touches the disk or the screen except through the kernel.

a task is a single thread of execution. a process is a task together with a loaded program and a working directory. the system holds up to sixty-four of each. when both are exhausted, no further programs can be started until something exits.

libraries are modules of code loaded from disk on demand. the kernel does not link programs in advance; the library manager fetches each library the first time it is named, and keeps it in memory until the system shuts down. up to sixty-four libraries may be loaded at once.

the console is the operator's only window into the running system. it is a fixed text grid and a keyboard, provided by the opcon library. there is no second screen, no log file the operator must tail, and no graphical mode.

files and volumes are how the disk is organised. a volume is a mounted unit of storage; each volume sits on a letter drive. files live in directories within a volume. there is no shared root above the drives.

messages are how tasks talk. one task sends, another receives, the receiver replies. the operator never sees a message change hands, but every service the system offers, including the disk, the console, and the library manager, is reached this way.

the operator should keep one distinction in mind. some things are resident in the kernel and are always there: the scheduler, the message dispatch, the memory pool. other things are loaded only when needed: libraries, programs, the shell itself. a fault in something resident stops the machine; a fault in something loaded stops only that one program.

the console

command line

the console runs the almac shell. the prompt is a greater-than sign followed by a space:

>

when a line of input is not yet complete, for example an unclosed compound or an unfinished expression, the shell continues the line with a period and a space:

> fn greet ():
.   say "hello";;

whatever the operator types at the prompt is almac source. there are no separate shell commands in the unix sense. the resident commands listed later in this manual are functions that the shell makes available at the prompt with no import required.

to run an app, the operator imports its module and calls its entry function:

> import '/a/tools/jot
> jot.in '/a/notes/today

editing

backspace deletes the character to the left of the cursor. enter submits the line. tab inserts two spaces; the shell does not align to a tab stop. a single input line holds up to two hundred and fifty-six characters. a multi-line entry, that is text typed across continuation prompts, holds up to four thousand and ninety-six characters in total. when either limit is reached the shell refuses further input on that entry; the operator must submit or abandon what is already typed.

sessions

a complete short session, from prompt to prompt:

> import '/a/tools/jot
> jot.in '/a/notes/today
... editor takes the screen, operator edits, ctrl-s saves, ctrl-q exits
> ls
notes
tools
games
init
almac
>

the startup script

when the shell begins, after the boot sequence has completed and before the first prompt is issued, it looks for the file /a/almac/rc.alm. if the file is present, the shell evaluates it as almac source in the global namespace. if it is absent, the shell proceeds directly to the prompt.

rc.alm is the operator's point of customisation. the operator places in it any imports that should be in effect at the prompt without typing them by hand, and any functions that the operator wishes to call without first loading a module. anything defined in rc.alm is visible at the prompt thereafter, exactly as if the operator had typed it at the first prompt.

a short example. an operator who reads the system log daily might keep:

import '/a/tools/gaze

fn log () raises:
  gaze.at '/a/notes/log;;

after boot, the operator types log at the prompt and the pager opens on the log file. a zero-argument call needs no parentheses; the shell calls log automatically because the prompt expects a value, not a function.

rc.alm is itself a text file and is edited with jot. an installation that does not require any customisation may omit the file entirely; the shell will not complain about its absence.

files, volumes and devices

paths take the form of a slash, a drive letter, a slash, and the path within the drive. forward slash separates directory components. a single dot refers to the current directory; two dots refer to the parent. a path that does not begin with a slash is taken as relative to the working directory.

drive a is the boot volume. it holds the kernel image, the system libraries in /a/init/a, the shell in /a/almac, the tools in /a/tools, the games in /a/games, and whatever files the operator has placed on the disk. drive a is read-write.

drive b, when present, is a read-only passthrough to the filesystem of the machine that hosts aldan. it appears only when the machine was started with host access enabled, and is absent on a sealed installation. the operator should not assume drive b is available.

devices are referred to by role, not by port. the operator names the keyboard, the display, the disk, or the sound channel; the kernel resolves the name. there are no port numbers, no interrupt vectors, and no device addresses for the operator to learn.

the disk server is a single task that holds the disk. every read and every write, from the shell, from a library, or from a program, is queued through it. the operator should not assume that two writes issued in quick succession are interleaved; they are serialised, in the order the disk server received them.

booting

booting is the sequence from power-on to the first prompt. the operator's role begins at the moment the machine is powered; the firmware needs no input and the operator may not interrupt it.

each step of the boot prints a line to the console as it completes. an operator who watches the console during boot can identify the last step that succeeded.

if the boot does not reach the prompt, the operator should read the console. the last line printed names the step that did not complete. the operator should suspect, in order: a corrupt or missing file at the named step, a damaged adfs partition, and a hardware fault. specific diagnostic codes are not yet stable and are not listed here.

programs

a program in aldos is a file in the rune format. it has the extension .run and contains four sections, the code, the read-only data, the mutable data, and a reservation for the stack, together with a table of relocations the loader applies when the file is brought into memory. the rune header carries a magic number and a machine identifier; the loader will refuse a file with the wrong machine.

a library is a rune file with the extension .lib. it differs from a .run only in what its entry function returns: a library returns the address of a vtable through which other code calls into it. the library manager identifies libraries by base name alone, and two libraries that share a base name cannot both be loaded.

the lifecycle of a program is fixed. the loader opens the file, validates the magic and the machine, allocates memory for the four sections, copies them in, applies the relocations, zeroes the uninitialised data, and jumps to the entry. when the entry returns, the runtime calls each registered destructor in reverse order of registration, and the kernel reclaims the process slot.

almac source files have the extension .alm. they are not executables; they are text. the shell compiles them on demand when the operator imports them.

command reference

each entry in this section follows the same form: name, synopsis, description, options, examples, and notes. a field that does not apply is written with the value "none". the commands are grouped in two parts. resident commands are bound at the shell prompt and may be called without an import. transient commands are apps loaded from the disk on demand; the operator imports the module by name before calling its entry.

resident commands.

import

name: import.

synopsis: import 'name. import 'name, 'name, ...

description: load a library from the disk. the operator gives the path to the library file, without the .lib extension. several libraries may be loaded with a single import. a library that initmgr has already loaded at boot, that is, one of those in /a/init/a, may be referred to by its base name alone.

options: none.

examples:

> import '/a/tools/jot
> import '/a/tools/gaze, '/a/games/snake

notes: a library that is already loaded is not loaded again. an import that names a library the manager cannot find raises a fault and the line is rejected.

say

name: say.

synopsis: say expression { "," expression }.

description: write each expression to the console; a newline is appended after the last. several values may be passed in one call.

options: none.

examples:

> say "hello"
hello
> say (1 + 2)
3
> say "x = ", 42
x = 42

notes: none.

sayin

name: sayin.

synopsis: sayin expression { "," expression }.

description: write each expression to the console with no trailing newline. used when the operator wishes to build a single line of output from several calls.

options: none.

examples:

> sayin "x = "
> say 42
x = 42

notes: none.

ls

name: ls.

synopsis: ls.

description: list the entries in the current working directory. each entry is written on its own line.

options: none.

examples:

> ls
[ ".", "..", "tools", "games", "init", "almac" ]

notes: ls lists the current working directory only and takes no argument. to list another directory, the operator changes into it first with cd.

cd

name: cd.

synopsis: cd 'path.

description: change the working directory to the named path. returns the new working directory as a string.

options: none.

examples:

> cd '/a/notes
/a/notes
> cd '..
/a

notes: there is no resident pwd command. to read the current working directory without changing it, the operator may call cd with '. as the argument; the return value is the working directory.

mkdir

name: mkdir.

synopsis: mkdir 'path.

description: create a new directory at the named path. the parent of the new directory must exist.

options: none.

examples:

> mkdir '/a/notes

notes: mkdir creates a single directory. to create a chain of directories, the operator calls mkdir on each in turn.

rmdir

name: rmdir.

synopsis: rmdir 'path.

description: remove the named directory. the directory must be empty.

options: none.

examples:

> rmdir '/a/notes

notes: rmdir will not remove a directory that contains files or sub-directories. the operator should rm the contents first.

touch

name: touch.

synopsis: touch 'path.

description: if the named file does not exist, create it as an empty file. if it does exist, update its timestamp.

options: none.

examples:

> touch '/a/notes/today

notes: touch does not create the parent directory.

rm

name: rm.

synopsis: rm 'path.

description: remove the named file.

options: none.

examples:

> rm '/a/notes/old

notes: rm removes a single file and does not remove directories. there is no confirmation prompt and there is no recovery.

cat

name: cat.

synopsis: cat 'path.

description: write the contents of the named file to the console.

options: none.

examples:

> cat '/a/notes/today
buy bread.
fix the disk light.

notes: cat is intended for short text files. for a longer file the operator should use gaze.

cp

name: cp.

synopsis: cp 'source, 'destination.

description: copy the source file to the destination. the destination is overwritten if it exists.

options: none.

examples:

> cp '/a/notes/today, '/a/notes/yesterday

notes: cp copies a single file. the destination's parent directory must exist.

mv

name: mv.

synopsis: mv 'source, 'destination.

description: move or rename the source file to the destination. used to rename a file within a directory and to move a file from one directory to another.

options: none.

examples:

> mv '/a/notes/old, '/a/archive/old

notes: mv operates on a single file. the destination's parent directory must exist.

transient commands.

jot

name: jot.

synopsis: jot.in 'path.

description: a full-screen text editor. jot takes the console, loads the named file into a buffer, and lets the operator move the cursor with the arrow keys and edit the buffer in place. ctrl-s writes the buffer to the file. ctrl-q exits and returns the console to the shell.

options: none.

examples:

> import '/a/tools/jot
> jot.in '/a/notes/today
... editor takes the screen, operator edits, ctrl-s saves, ctrl-q exits
>

notes: jot edits in memory. no change is written to the disk until the operator presses ctrl-s. an operator who quits with ctrl-q before saving will lose every change made since the last save.

gaze

name: gaze.

synopsis: gaze.at 'path.

description: a pager for reading a file too long to cat. gaze takes the console, displays the first page of the file, and lets the operator scroll. the arrow keys scroll one line at a time; page-up and page-down scroll half a page. ctrl-q exits.

options: none.

examples:

> import '/a/tools/gaze
> gaze.at '/a/notes/log
... file fills the screen, operator scrolls, ctrl-q exits
>

notes: gaze is read-only. the operator may scroll but cannot edit. to edit a file, use jot.

snake

name: snake.

synopsis: snake.play.

description: a game. a snake moves across the screen, lengthening when it eats and ending when it strikes a wall or itself. the arrow keys steer. ctrl-q exits.

options: none.

examples:

> import '/a/games/snake
> snake.play
... game runs, operator steers, ctrl-q exits
>

notes: the score is shown at the top of the screen and is not preserved between runs.