Orb is an operating system designed for embedding in a game in order to facilitate learning programming and unix skills.
You can use the OS from the CLI outside the game too:
$ lua init.lua
However, when run this way it uses blocking input, which will prevent the scheduler from running more than one process. (This means you can't pipe from one process to another, as this requires at least some level of faux-concurrency.) Note the filesystem is purely in-memory in the Lua process and will not persist when run from the CLI, though when running in-game it should be persisted in between server restarts.
Upon boot, the scripts inside the
resources directory will be copied
into the in-memory filesystem. Running the
reload command will
refresh the inner filesystem from the real filesystem.
Most functions take a filesystem table and an environment table. The environment table is like what you'd expect; it simply maps strings to strings. The filesystem is a bit more complicated. It's a tree where directories are just tables, regular files are just strings, and special nodes are functions. Write to a special node by calling a function with arguments, and read from it by calling it with no arguments.
Further, there are two types of filesystems. Raw filesystems are
regular tables, but they are not used very much. Proxied filesystems
are tables wrapped with metatables that enforce read/write permissions
for a given user. In addition, proxied filesystems support lookup
fs["/path/to/file"], whereas this would fail with a raw
filesystem; it would need to use
fs.path.to.file instead. Most
functions assume they have a proxied filesystem.
Group membership is implemented by placing a file in
/etc/group/$GROUP named after the user in question.
The shell is sandboxed and only has access to the whitelist in
orb.process.sandbox, which is currently rather small. Since the
environment is just a table, it can be modified at will by user
code. Sandbox functions which need to trust the
value must be wrapped in order to ensure it hasn't changed.
Spawning processes places entries in the
/proc/$USER/ table. The key
is the process id, and the value is a coroutine for that process. The
scheduler currently runs by looping over all the coroutines in the
/proc directory and resuming each of them.
- smash (bash-like)
Other shell features
- sandbox scripts (limited api access)
- enforce access controls in the filesystem
- input/output redirection
- env var interpolation
- user passwords
- pipes (half-implemented)
- quoting in shell args
- pre-emptive multitasking (see this thread for implementation ideas)
- /proc nodes for exposing connected digiline peripherals
- more of the built-in scripts should take multiple target arguments
Differences from Unix
The OS is an attempt at being unix-like; however, it varies in several ways. Some of them are due to conceptual simplification; some are in order to have an easier time implementing it given the target platform, and some are due to oversight/mistakes or unfinished features.
The biggest difference is that of permissions. In this system,
permissions only belong to directories, and files are simply subject
to the permissions of the directory containing them. In addition, the
of unix are collapsed into a single
group_write bit. It's assumed
that the directory's owner always has full read-write access and that
members of the group always have read access. The
commands work similarly as to unix, but
chmod simply takes a
- argument to enable or disable group write. Group membership is
indicated simply by an entry in the
named after the username.
Rather than traditional stdio kept in
/dev/, here we have
OUT filenames kept in the environment, and
default to using these. There is no stderr. Due to limitations
in the engine, there is no character-by-character IO; it is only full
strings (usually a whole line) at a time that are passed to
read. The sandbox in which scripts run have
io.read redefined to these functions; when a session
is initiated over the terminal it's up to the node definition to set
OUT in the environment to functions which move the data
to and from the terminal's connection.
Of course, all scripts are written in Lua. Filesystem, the environment
table, and CLI args are exposed as
..., so scripts typically start
local f, env, args = .... Filesystem access is simply table
access, though the table you're given is a proxy table that enforces
permissions with Lua metamethods. Regular files in the filesystem are
just strings in a table, and special nodes (like named pipes) are
Sudo takes the user to switch to as its first argument, and the
following arguments are taken as a command to run as the other
user. There is no password required; if you are in the
group, you can run sudo.
You can refer to environment variables in shell commands, but the
$VAR does not work; you must use the less-ambiguous
Currently when running outside of minetest it needs to shell out to
sha1sum executable because Lua does not have any built-in
checksumming functionality. This could pose a problem when running on
platforms that lack this executable.
Copyright © 2015 Phil Hagelberg and contributors. Licensed under the GPLv3 or later; see the file COPYING.