1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# The ucode Language
The ucode language is a tiny general purpose scripting language featuring a
syntax closely resembling ECMAScript. It can be used in a stand-alone manner
by using the ucode command line interpreter or embedded into host applications
by linking libucode and utilizing its C language API. Additionally, ucode can
be invoked in template mode where control flow and expression logic statements
are embedded in Jinja-like markup blocks.
Besides aiming for small size, the major design goals of ucode are the ability
to trivially read and write JSON data, good embeddability into C applications,
template capabilities for output formatting, extensiblity through loadable
native extension modules and a straightforward set of built-in functions
mimicking those found in the Perl 5 language.
## History and Motivation
In spring 2021 it has been decided to rewrite the OpenWrt firewall framework on
top of nftables with the goal to replace the then current C application with a
kind of preprocessor generating nftables rulesets using a set of templates
instead of relying on built-in hardcoded rules like its predecessor.
That decision spurred the development of *ucode*, initially meant to be a
simple template processor solely for the OpenWrt nftables firewall but quickly
evolving into a general purpose scripting language suitable for a wider range
of system scripting tasks.
Despite OpenWrt predominantly relying on POSIX shell and Lua as system
scripting languages already, a new solution was needed to accomodate the needs
of the new firewall implementation; mainly the ability to efficiently deal with
JSON data and complex data structures such as arrays and dictionaries and the
ability to closely interface with OpenWrt's *ubus* message bus system.
Throughout the design process of the new firewall and its template processor,
the following design goals were defined for the *ucode* scripting language:
- Ability to embed code logic fragments such as control flow statements,
function calls or arithmetic expressions into plain text templates, using
a block syntax and functionality roughly inspired by Jinja templates
- Built-in support for JSON data parsing and serialization, without the need
for external libraries
- Distinct array and object types (compared to Lua's single table datatype)
- Distinct integer and float types and guaranteed 64bit integer range
- Built-in support for bit operations
- Built-in support for (POSIX) regular expressions
- A comprehensive set of built-in standard functions, inspired by the core
functions found in the Perl 5 interpreter
- Staying as close to ECMAScript syntax as possible due to higher developer
familiarity and to be able to reuse existing tooling such as editor syntax
highlighting
- Bindings for all relevant Linux and OpenWrt APIs, such as *ubus*, *uci*,
*uloop*, *netlink* etc.
- Procedural, synchronous programming flow
- Very small executable size (the interpreter and runtime is currently around
64KB on ARM Cortex A9)
- Embeddability into C host applications
Summarized, *ucode* can be described as synchronous ECMAScript without the
object oriented standard library.
## Installation
### OpenWrt
In OpenWrt 22.03 and later, *ucode* should already be preinstalled. If not,
it can be installed via the package manager, using the `opkg install ucode`
command.
### MacOS
To build on MacOS, first install *cmake* and *json-c* via
[Homebrew](https://brew.sh/), then clone the ucode repository and execute
*cmake* followed by *make*:
$ brew install cmake json-c
$ git clone https://github.com/jow-/ucode.git
$ cd ucode/
$ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF .
$ make
$ sudo make install
### Debian
The ucode repository contains build recipes for Debian packages, to build .deb
packages for local installation, first install required development packages,
then clone the repository and invoke *dpkg-buildpackage* to produce the binary
package files:
$ sudo apt-get install build-essential devscripts debhelper libjson-c-dev cmake pkg-config
$ git clone https://github.com/jow-/ucode.git
$ cd ucode/
$ dpkg-buildpackage -b -us -uc
$ sudo dpkg -i ../ucode*.deb ../libucode*.deb
### Other Linux systems
To install ucode from source on other systems, ensure that the json-c library
and associated development headers are installed, then clone and compile the
ucode repository:
$ git clone https://github.com/jow-/ucode.git
$ cd ucode/
$ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF .
$ make
$ sudo make install
|