Age | Commit message (Collapse) | Author |
|
- Parse integer literals as unsigned numeric values in order to be able
to represent the entire unsigned 64bit value range
- Stop parsing minus-prefixed integer literals as negative numbers but
treat them as separate minus operator followed by a positive integer
instead
- Only store unsigned numeric constants in bytecode
- Rework numeric comparison logic to be able to handle full 64bit
unsigned integers
- If possible, yield unsigned 64 bit results for additions
- Simplify numeric value conversion API
- Compile code with -fwrapv for defined signed overflow semantics
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Implement support for opening existing file descriptors as well as acquiring
the descriptor number from open process and file handles.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a new ubus.defer() method which initiates asynchroneous requests
and invokes the completion callback passed as 4th argument once the reply
is received.
This allows multiplexing mutliple ubus requests with the same ucode VM
context / the same uloop event loop.
In case the ucode context is not running under an active uloop, the ubus
module will spawn uloop itself once the first asynchroneous request is
launched and terminate the loop once all pending requests finished.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The nl_recvmsgs() logic in uc_nl_request() incorrectly stopped reading
the socket before the netlink ACK message was handled for non-multipart
replies.
This caused subsequent requests to incorrectly receive the ACK of the
previous request, leading to a failure to receive the actual reply.
Fix this issue by continue reading the socket until either the finish
callback for multipart (dump) messages or the ack callback for non-
multipart messages was received.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Add three new functions `dirname()`, `basename()` and `lsdir()`.
The `basename()` and `dirname()` functions behave like their libc
counterparts and return the filename and directory portion of a
given path respectively. If the path argument is missing or not
a string, null is returned.
Examples:
dirname("/usr/lib") -> "/usr"
dirname("/usr/") -> "/"
dirname("usr") -> "."
dirname("/") -> "/"
dirname(".") -> "."
dirname("..") -> "."
basename("/usr/lib") -> "lib"
basename("/usr/") -> "usr"
basename("usr") -> "usr"
basename("/") -> "/"
basename(".") -> "."
basename("..") -> ".."
The `lsdir()` function returns a sorted array containing the names
of all entries within the given directory path, without the common
"." and ".." entries. If the given path is not a directory, cannot
be opened or if another system level occurs, null is returned and
`fs.error()` can be used to query details.
The function takes an optional second argument which may be either a
regular expression value or a string. In case a regular expression
is given, each directory entry is matched against it. In case a
string is provided, it is treated as wildcard (glob) pattern and
only directory entries matching the pattern are considered.
Examples:
lsdir("/sys/class/net") -> [ "eth0", "lo", "wlan0" ]
lsdir("/proc", /^[0-9]+$/) -> [ "1", "4", "12", ... ]
lsdir("/sys/class/block/", "sd?3") -> [ "sde3", "sdf3" ]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Extract the wiphy index from the response message and use it to select
the item to merge the fragment information into.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fix instances of misspelled "resource".
This commit breaks the exported libucode ABI.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The "align" pragma was accidentally renamed while refactoring the
original module code.
Fixes: 402f603 ("lib: introduce struct library")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a new "struct" library which is a port of the Python 3.10 struct
module with a reduced set of API functions. It supports the same format
patterns and conversions while providing the following methods:
struct = require('struct');
buf = struct.pack("fmt", args...);
values = struct.unpack("fmt", buf);
struct_inst = struct.new("fmt");
buf = struct_inst.pack(args...);
values = struct_inst.unpack(buf);
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
This adds a simple, UDP-only DNS resolver library mimicking the operation of
the extended busybox nslookup applet.
Simply querying a domain name will perform A + AAAA resolving by default:
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("example.com"))'
{
"example.com": {
"A": [
"93.184.216.34"
],
"AAAA": [
"2606:2800:220:1:248:1893:25c8:1946"
]
}
}
Passing IP addresses will automatically perform PTR requests:
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("8.8.8.8"))'
{
"8.8.8.8.in-addr.arpa": {
"PTR": [
"dns.google"
]
}
}
# ucode -mresolv -Rs 'printf("%.J\n", resolv.query("2001:4860:4860::8888"))'
{
"8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa": {
"PTR": [
"dns.google"
]
}
}
Additional options for query type and nameserver selection can be passed via
a second optional options dictionary:
# ucode -mresolv -Rs 'printf("%.J\n",
resolv.query([ "openwrt.org", "example.org", "doesnotexist.tld" ], {
type: [ "A", "AAAA", "MX" ],
nameserver: [ "1.1.1.1", "8.8.4.4" ],
timeout: 5000,
retries: 2,
edns_maxsize: 4096
}))'
{
"openwrt.org": {
"A": [
"139.59.209.225"
],
"MX": [
[
10,
"util-01.infra.openwrt.org"
]
],
"AAAA": [
"2a03:b0c0:3:d0::1af1:1"
]
},
"example.org": {
"A": [
"93.184.216.34"
],
"AAAA": [
"2606:2800:220:1:248:1893:25c8:1946"
],
"MX": [
[
0,
"."
]
]
},
"doesnotexist.tld": {
"rcode": "NXDOMAIN"
}
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
# ucode -mrtnl -Rs 'printf("%.J", rtnl.request(rtnl.const.RTM_GETROUTE, 0, { dst: "8.8.8.8" }))'
{
"family": 2,
"tos": 0,
"protocol": 0,
"scope": 0,
"type": 1,
"flags": 512,
"dst": "8.8.8.8/32",
"oif": "onboard",
"gateway": "10.11.12.13",
"prefsrc": "10.11.12.7",
"cacheinfo": {
"clntref": 2,
"lastuse": 0,
"expires": 0,
"error": 0,
"used": 0,
"id": 0,
"ts": 0,
"tsage": 0
},
"table": 254,
"uid": 0
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
# ucode -mrtnl -Rs 'printf("%.J", rtnl.request(rtnl.const.RTM_GETLINK, 0, { dev: "lo" }))'
{
"family": 0,
"type": 772,
"dev": "lo",
"flags": 65609,
"address": "00:00:00:00:00:00",
"broadcast": "00:00:00:00:00:00",
"txqlen": 1000,
"mtu": 65536,
"carrier": true,
"linkmode": 0,
"operstate": 0,
"num_tx_queues": 1,
"num_rx_queues": 1,
"af_spec": {
"inet": {
"conf": {
"forwarding": 1,
"mc_forwarding": 0,
"proxy_arp": 0,
"accept_redirects": 1,
"secure_redirects": 1,
"send_redirects": 1,
"shared_media": 1,
"rp_filter": 0,
"accept_source_route": 1,
"bootp_relay": 0,
"log_martians": 0,
"tag": 0,
"arpfilter": 0,
"medium_id": 0,
"noxfrm": 1,
"nopolicy": 1,
"force_igmp_version": 0,
"arp_announce": 0,
"arp_ignore": 0,
"promote_secondaries": 0,
"arp_accept": 0,
"arp_notify": 0,
"accept_local": 0,
"src_vmark": 0,
"proxy_arp_pvlan": 0,
"route_localnet": 0,
"igmpv2_unsolicited_report_interval": 10000,
"igmpv3_unsolicited_report_interval": 1000,
"ignore_routes_with_linkdown": 0,
"drop_unicast_in_l2_multicast": 0,
"drop_gratuitous_arp": 0,
"bc_forwarding": 0
}
},
"inet6": {
"mode": 0,
"flags": 2147483648,
"conf": {
"forwarding": 0,
"hoplimit": 64,
"mtu6": 65536,
"accept_ra": 1,
"accept_redirects": 1,
"autoconf": 1,
"dad_transmits": 1,
"rtr_solicits": -1,
"rtr_solicit_interval": 4000,
"rtr_solicit_delay": 1000,
"use_tempaddr": -1,
"temp_valid_lft": 604800,
"temp_prefered_lft": 86400,
"regen_max_retry": 3,
"max_desync_factor": 600,
"max_addresses": 16,
"force_mld_version": 0,
"accept_ra_defrtr": 1,
"accept_ra_pinfo": 1,
"accept_ra_rtr_pref": 1,
"rtr_probe_interval": 60000,
"accept_ra_rt_info_max_plen": 0,
"proxy_ndp": 0,
"optimistic_dad": 0,
"accept_source_route": 0,
"mc_forwarding": 0,
"disable_ipv6": 0,
"accept_dad": -1,
"force_tllao": 0,
"ndisc_notify": 0,
"mldv1_unsolicited_report_interval": 10000,
"mldv2_unsolicited_report_interval": 1000,
"suppress_frag_ndisc": 1,
"accept_ra_from_local": 0,
"use_optimistic": 0,
"accept_ra_mtu": 1,
"stable_secret": 0,
"use_oif_addrs_only": 0,
"accept_ra_min_hop_limit": 1,
"ignore_routes_with_linkdown": 0,
"drop_unicast_in_l2_multicast": 0,
"drop_unsolicited_na": 0,
"keep_addr_on_down": 0,
"rtr_solicit_max_interval": 3600000,
"seg6_enabled": 0,
"seg6_require_hmac": 0,
"enhanced_dad": 1,
"addr_gen_mode": 0,
"disable_policy": 0,
"accept_ra_rt_info_min_plen": 0,
"ndisc_tclass": 0,
"rpl_seg_enabled": 0
}
}
},
"proto_down": false,
"group": 0,
"ifname": "lo"
}
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Some netlink replies contain attributes with embeded payloads whose
length depends on the kernel version, e.g. IFLA_INET_CONF and
IFLA_INET6_CONF.
Deal with such cases by allowing the payloads to be shorter than
the expected size and by skipping struct members which would lead
to out-of-bounds accesses.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fixes: dfb7379 ("fs: implement chmod(), chown(), rename() and glob() functions")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Ensure that most functions follow the subject_verb naming schema
- Move type related function from value.c to types.c
- Rename value.c to vallist.c
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Ensure that all custom typedef and vector declaration type names end with
a "_t" suffix.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The naming is an artifact from before the introduction of the new type
system. In the current code, there is nothing special about prototypes,
they're simple object values.
Also introduce a new singular uc_add_function() convenience macro while
we're at it.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- The chmod() function expects a path string as first and an integer mode
value as second argument.
- The chown() function takes a path string as first argument, and either
a string, an integer or null as second user and third group argument
respectively.
If either user or group are given as string, they're resolved to an
uid/gid using getpwnam()/getgrnam() internally. If either lookup fails,
the ownership change is not performed.
If either user or group are null or -1, they're left unchanged.
- The rename() function takes two path strings, the old path being the
first argument and the new path the second one.
- The glob() function takes an arbitrary number of glob patterns and
resolves matching files for each one. In case of multiple patterns,
no efforts are made to remove duplicates or to globally sort the combined
match list. The list of matches for each individual pattern is sorted.
Returns an array containing all matched file paths.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Shuffle typedefs to avoid need for non-compliant forward declarations
- Fix non-compliant empty struct initializers
- Remove use of braced expressions
- Remove use of anonymous unions
- Avoid `void *` pointer arithmetic
- Fix several warnings reported by gcc -pedantic mode and clang 11 compilation
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Instead of relying on json_object values internally, use custom types to
represent the different ucode value types which brings a number of
advantages compared to the previous approach:
- Due to the use of tagged pointers, small integer, string and bool
values can be stored directly in the pointer addresses, vastly
reducing required heap memory
- Ability to create circular data structures such as
`let o; o = { test: o };`
- Ability to register custom `tostring()` function through prototypes
- Initial mark/sweep GC implementation to tear down circular object
graphs on VM deinit
The change also paves the way for possible future extensions such as
constant variables and meta methods for custom ressource types.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Check the numerical error code index before attempting to look it up in
the error string array.
Also make error function available on the cursor instance as well.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The fs.readlink() function incorrectly produced a JSON string containing
trailing null bytes.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Replace the former AST walking interpreter implementation with a single pass
bytecode compiler and a corresponding virtual machine.
The rewrite lays the groundwork for a couple of improvements with will be
subsequently implemented:
- Ability to precompile ucode sources into binary byte code
- Strippable debug information
- Reduced runtime memory usage
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Also handle calls to C functions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Register prototype object directly together with the type instead of
setting it manually whenever an extended type value is instantiated.
This also allows freeing the various prototype objects in dlopened
modules.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Also introduce convenience macro for registering function arrays in modules.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Also move shared library output files to the lib/ directory
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|