diff --git a/.bazelrc b/.bazelrc index c47472bdad..2a72ab5654 100644 --- a/.bazelrc +++ b/.bazelrc @@ -20,19 +20,21 @@ build --@io_bazel_rules_docker//transitions:enable=false build --flag_alias=clang_version=//:clang_version build --flag_alias=gcc_version=//:gcc_version +# Use optimized build by default. According to the bazel documentation, this +# corresponds to -O2 -DNDEBUG, but these are overriden in +# //bazel/common_settings.bzl:vere_library. +# https://bazel.build/docs/user-manual#build-semantics +build --compilation_mode=opt + # Don't include source level debug info on macOS. See # https://github.com/urbit/urbit/issues/5561 and # https://github.com/urbit/vere/issues/131. -build:linux --per_file_copt='pkg/.*@-g' build:linux --host_copt='-g' build --strip=never -# Use -O3 as the default optimization level. -build --per_file_copt='pkg/.*@-O3' +# Turn on optimization, CPU and memory debug for exec config, which we only use +# to run the fake ship tests. Also turn on extra snapshot validation. build --host_copt='-O3' - -# Turn on CPU and memory debug for exec config, which we only use to run the -# fake ship tests. Also turn on extra snapshot validation. build --host_copt='-DU3_CPU_DEBUG' build --host_copt='-DU3_MEMORY_DEBUG' build --host_copt='-DC3DBG' @@ -45,12 +47,5 @@ build:mem_dbg --per_file_copt='pkg/.*@-DU3_MEMORY_DEBUG' build:cpu_dbg --per_file_copt='pkg/.*@-DU3_CPU_DEBUG' build:snp_dbg --per_file_copt='pkg/.*@-DU3_SNAPSHOT_VALIDATION' -# Enable maximum debug info and disable optimizations for debug config. It's -# important that these lines come after setting the default debug and -# optimization level flags above. -build:dbg --per_file_copt='pkg/.*@-O0' -build:dbg --per_file_copt='pkg/.*@-g3' -build:dbg --per_file_copt='pkg/.*@-DC3DBG' - # Any personal configuration should go in .user.bazelrc. try-import %workspace%/.user.bazelrc diff --git a/BUILD.bazel b/BUILD.bazel index 304ecb66d4..ff11949f5f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -37,6 +37,38 @@ config_setting( ], ) +# +# CONFIGS DETAILING WHEN TO ENABLE CERTAIN FEATURES BY DEFAULT. +# CHANGES BEHAVIOR OF //bazel/common_settings.bzl:vere_library. +# + +config_setting( + name = "thinlto", + constraint_values = [ + "@platforms//os:macos", + ], + values = { + "compilation_mode": "opt" + } +) + +config_setting( + name = "lto", + constraint_values = [ + "@platforms//os:linux", + ], + values = { + "compilation_mode": "opt" + } +) + +config_setting( + name = "debug", + values = { + "compilation_mode": "dbg" + } +) + # # COMPILERS # diff --git a/INSTALL.md b/INSTALL.md index f9eb54c42e..e30f14f88e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -60,9 +60,10 @@ bazel build :urbit ``` If you want a debug build, which changes the optimization level from `-O3` to -`-O0` and includes more debugging information, specify the `dbg` configuration: +`-O0` and includes more debugging information, specify `dbg` as the +`compilation_mode`: ```console -bazel build --config=dbg :urbit +bazel build --compilation_mode=dbg :urbit ``` Note that you cannot change the optimization level for third party dependencies--those targets specified in `bazel/third_party`--from the command diff --git a/VERSION b/VERSION index 6a5fe6e897..3e162f02ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.11 +2.12 diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 56a347ed6d..2cad948ace 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -358,10 +358,10 @@ versioned_http_archive( versioned_http_archive( name = "zlib", build_file = "//bazel/third_party/zlib:zlib.BUILD", - sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30", + sha256 = "ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e", strip_prefix = "zlib-{version}", url = "https://www.zlib.net/zlib-{version}.tar.gz", - version = "1.2.13", + version = "1.3", ) # diff --git a/bazel/common_settings.bzl b/bazel/common_settings.bzl index 945447d3c5..6a61de1292 100644 --- a/bazel/common_settings.bzl +++ b/bazel/common_settings.bzl @@ -10,3 +10,50 @@ string_flag = rule( build_setting = config.string(flag = True), doc = "A string-typed build setting that can be set on the command line", ) + +def vere_library(copts = [], linkopts = [], **kwargs): + native.cc_library( + copts = copts + select({ + "//:debug": ["-O0", "-g3", "-DC3DBG"], + "//conditions:default": ["-O3"] + }) + select({ + "//:lto": ['-flto'], + "//:thinlto": ['-flto=thin'], + "//conditions:default": [] + }) + select({ + # Don't include source level debug info on macOS. See + # https://github.com/urbit/urbit/issues/5561 and + # https://github.com/urbit/vere/issues/131. + "//:debug": [], + "@platforms//os:linux": ["-g"], + "//conditions:default": [], + }), + linkopts = linkopts + ['-g'] + select({ + "//:lto": ['-flto'], + "//:thinlto": ['-flto=thin'], + "//conditions:default": [] + }), + **kwargs, + ) + +def vere_binary(copts = [], linkopts = [], **kwargs): + native.cc_binary( + copts = copts + select({ + "//:debug": ["-O0", "-g3", "-DC3DBG"], + "//conditions:default": ["-O3"] + }) + select({ + "//:lto": ['-flto'], + "//:thinlto": ['-flto=thin'], + "//conditions:default": [] + }) + select({ + "//:debug": [], + "@platforms//os:linux": ["-g"], + "//conditions:default": [], + }), + linkopts = linkopts + ['-g'] + select({ + "//:lto": ['-flto'], + "//:thinlto": ['-flto=thin'], + "//conditions:default": [] + }), + **kwargs, + ) diff --git a/bazel/toolchain/BUILD.bazel b/bazel/toolchain/BUILD.bazel index a68b1a2284..aaed5de087 100644 --- a/bazel/toolchain/BUILD.bazel +++ b/bazel/toolchain/BUILD.bazel @@ -50,7 +50,7 @@ _aarch64_gcc = "toolchain-gcc-linux-aarch64" cc_toolchain_config( name = "gcc-linux-aarch64-config", - ar = "{}/aarch64-linux-musl/bin/aarch64-linux-musl-ar".format(_install_prefix), + ar = "{}/aarch64-linux-musl/bin/aarch64-linux-musl-gcc-ar".format(_install_prefix), cc = "{}/aarch64-linux-musl/bin/aarch64-linux-musl-gcc".format(_install_prefix), cc_flags = [ "-static", @@ -104,7 +104,7 @@ _x86_64_gcc = "toolchain-gcc-linux-x86_64" cc_toolchain_config( name = "gcc-linux-x86_64-config", - ar = "{}/x86_64-linux-musl/bin/x86_64-linux-musl-ar".format(_install_prefix), + ar = "{}/x86_64-linux-musl/bin/x86_64-linux-musl-gcc-ar".format(_install_prefix), cc = "{}/x86_64-linux-musl/bin/x86_64-linux-musl-gcc".format(_install_prefix), cc_flags = [ "-static", @@ -279,7 +279,7 @@ cc_toolchain_config( # NOTE: building with `libtool` does not work on macOS due to lack of # support in the `configure_make` rule provided by `rules_foreign_cc`. # Therefore, we require setting `ar` as the archiver tool on macOS. - ar = "/usr/bin/ar", + ar = "/usr/local/opt/llvm@15/bin/llvm-ar", # By default, Bazel passes the `rcsD` flags to `ar`, but macOS's `ar` # implementation doesn't support `D`. We remove it with this attribute # and corresponding `ar_flags_feature` in `cfg.bzl`. @@ -288,7 +288,8 @@ cc_toolchain_config( cc = "/usr/local/opt/llvm@15/bin/clang", compiler = "clang", compiler_version = "//:clang_version", - ld = "/usr/bin/ld", + ld = "/usr/local/opt/llvm@15/bin/llvm-lld", + nm = "/usr/local/opt/llvm@15/bin/llvm-nm", sys_includes = [ "/usr/local/Cellar/llvm@15/15.0.7/lib/clang/15.0.7/include", "/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk/usr/include", diff --git a/flake.lock b/flake.lock index 12ffaf6f77..45c4d968fb 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1677383253, - "narHash": "sha256-UfpzWfSxkfXHnb4boXZNaKsAcUrZT9Hw+tao1oZxd08=", + "lastModified": 1683236849, + "narHash": "sha256-Y7PNBVLOBvZrmrFmHgXUBUA1lM72tl6JGIn1trOeuyE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9952d6bc395f5841262b006fbace8dd7e143b634", + "rev": "374ffe54403c3c42d97a513ac7a14ce1b5b86e30", "type": "github" }, "original": { @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1675933616, - "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=", + "lastModified": 1682984683, + "narHash": "sha256-fSMthG+tp60AHhNmaHc4StT3ltfHkQsJtN8GhfLWmtI=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "47478a4a003e745402acf63be7f9a092d51b83d7", + "rev": "86684881e184f41aa322e653880e497b66429f3e", "type": "github" }, "original": { diff --git a/pkg/c3/BUILD.bazel b/pkg/c3/BUILD.bazel index 45df2368db..95b790b5ec 100644 --- a/pkg/c3/BUILD.bazel +++ b/pkg/c3/BUILD.bazel @@ -2,7 +2,9 @@ # LIBRARIES # -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "c3", srcs = glob( [ diff --git a/pkg/c3/motes.h b/pkg/c3/motes.h index a9fd4b701e..0000d5c593 100644 --- a/pkg/c3/motes.h +++ b/pkg/c3/motes.h @@ -663,6 +663,7 @@ # define c3__ktts c3_s4('k','t','t','s') # define c3__ktwt c3_s4('k','t','w','t') # define c3__ktzp c3_s4('k','t','z','p') +# define c3__l c3_s1('l') # define c3__lamb c3_s4('l','a','m','b') # define c3__lame c3_s4('l','a','m','e') # define c3__lang c3_s4('l','a','n','g') @@ -686,6 +687,7 @@ # define c3__lg c3_s2('l','g') # define c3__lib c3_s3('l','i','b') # define c3__libd c3_s4('l','i','b','d') +# define c3__lick c3_s4('l','i','c','k') # define c3__life c3_s4('l','i','f','e') # define c3__lift c3_s4('l','i','f','t') # define c3__like c3_s4('l','i','k','e') @@ -1082,6 +1084,7 @@ # define c3__smts c3_s4('s','m','t','s') # define c3__snap c3_s4('s','n','a','p') # define c3__so c3_s2('s','o') +# define c3__soak c3_s4('s','o','a','k') # define c3__sock c3_s4('s','o','c','k') # define c3__soft c3_s4('s','o','f','t') # define c3__sole c3_s4('s','o','l','e') diff --git a/pkg/ent/BUILD.bazel b/pkg/ent/BUILD.bazel index c3c12e3de2..ad9894b1e2 100644 --- a/pkg/ent/BUILD.bazel +++ b/pkg/ent/BUILD.bazel @@ -2,7 +2,9 @@ # LIBRARIES # -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "ent", srcs = ["ent.c"], hdrs = ["ent.h"], diff --git a/pkg/noun/BUILD.bazel b/pkg/noun/BUILD.bazel index 393f649eb1..964e4bf60f 100644 --- a/pkg/noun/BUILD.bazel +++ b/pkg/noun/BUILD.bazel @@ -2,7 +2,9 @@ # LIBRARIES # -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "noun", srcs = glob( [ diff --git a/pkg/ur/BUILD.bazel b/pkg/ur/BUILD.bazel index e47e798702..4deff1e706 100644 --- a/pkg/ur/BUILD.bazel +++ b/pkg/ur/BUILD.bazel @@ -2,7 +2,9 @@ # LIBRARIES # -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "ur", srcs = [ "bitstream.c", diff --git a/pkg/urcrypt/BUILD.bazel b/pkg/urcrypt/BUILD.bazel index b4b3d79a4f..22108ea72c 100644 --- a/pkg/urcrypt/BUILD.bazel +++ b/pkg/urcrypt/BUILD.bazel @@ -2,7 +2,9 @@ # LIBRARIES # -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "urcrypt", srcs = glob( [ diff --git a/pkg/urcrypt/ge-additions/BUILD.bazel b/pkg/urcrypt/ge-additions/BUILD.bazel index 9dea2d305b..06ab7c3e5a 100644 --- a/pkg/urcrypt/ge-additions/BUILD.bazel +++ b/pkg/urcrypt/ge-additions/BUILD.bazel @@ -1,4 +1,6 @@ -cc_library( +load("//bazel:common_settings.bzl", "vere_library") + +vere_library( name = "ge-additions", srcs = ["ge-additions.c"], hdrs = ["ge-additions.h"], diff --git a/pkg/vere/BUILD.bazel b/pkg/vere/BUILD.bazel index b4d68ef44a..76f8b47eca 100644 --- a/pkg/vere/BUILD.bazel +++ b/pkg/vere/BUILD.bazel @@ -2,6 +2,8 @@ # GENERATED FILES # +load("//bazel:common_settings.bzl", "vere_library", "vere_binary") + # An approximation of `xxd -i` that runs on all platforms where Bash is # present. Generates a `.h` file that declares the array and array length as # `extern` global variables and a `.c` file containing the array and array @@ -86,7 +88,7 @@ genrule( # LIBRARIES # -cc_library( +vere_library( name = "vere", srcs = glob( [ @@ -138,7 +140,7 @@ cc_library( # BINARIES # -cc_binary( +vere_binary( name = "urbit", srcs = [ "main.c", diff --git a/pkg/vere/auto.c b/pkg/vere/auto.c index c5b4a57d93..2435458ad4 100644 --- a/pkg/vere/auto.c +++ b/pkg/vere/auto.c @@ -438,6 +438,7 @@ u3_auto_init(u3_pier* pir_u) car_u = _auto_link(u3_unix_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_term_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_fore_io_init(pir_u), pir_u, car_u); + car_u = _auto_link(u3_lick_io_init(pir_u), pir_u, car_u); return car_u; } diff --git a/pkg/vere/io/ames.c b/pkg/vere/io/ames.c index 185afad073..24baa6e042 100644 --- a/pkg/vere/io/ames.c +++ b/pkg/vere/io/ames.c @@ -55,6 +55,7 @@ c3_d fod_d; // forwards dropped count c3_d foq_d; // forward queue size c3_d fow_d; // forwarded count + c3_o for_o; // forwarding enabled c3_d hed_d; // failed to read header c3_d vet_d; // version mismatches filtered c3_d mut_d; // invalid mugs filtered @@ -1993,7 +1994,9 @@ _ames_hear(u3_ames* sam_u, && ( (pac_u->pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) || (pac_u->pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) { - _ames_try_forward(pac_u); + if ( c3y == sam_u->sat_u.for_o ) { + _ames_try_forward(pac_u); + } } else { // enter protocol-specific packet handling @@ -2458,6 +2461,11 @@ u3_ames_io_init(u3_pier* pir_u) sam_u->fig_u.see_o = c3y; sam_u->fig_u.fit_o = c3n; + // enable forwarding on galaxies only + u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); + u3_noun rac = u3do("clan:title", who); + sam_u->sat_u.for_o = ( c3__czar == rac ) ? c3y : c3n; + // hashtable for scry cache // // 1500 bytes per packet * 100_000 = 150MB diff --git a/pkg/vere/io/conn.c b/pkg/vere/io/conn.c index 1f381a2c6c..e89135adac 100644 --- a/pkg/vere/io/conn.c +++ b/pkg/vere/io/conn.c @@ -337,12 +337,9 @@ _conn_moor_bail(void* ptr_v, ssize_t err_i, const c3_c* err_c) if ( err_i != UV_EOF ) { u3l_log("conn: moor bail %zd %s", err_i, err_c); - if ( _(can_u->liv_o) ) { - _conn_send_noun(can_u, u3nq(0, c3__bail, u3i_word(err_i), - u3i_string(err_c))); - can_u->liv_o = c3n; - } + can_u->liv_o = c3n; } + _conn_close_chan(san_u, can_u); } diff --git a/pkg/vere/io/lick.c b/pkg/vere/io/lick.c new file mode 100644 index 0000000000..e420057246 --- /dev/null +++ b/pkg/vere/io/lick.c @@ -0,0 +1,646 @@ +/// @file + +#include "vere.h" +#include +#include +#include "noun.h" + +/* u3_chan: incoming ipc port connection. +*/ +typedef struct _u3_chan { + struct _u3_moor mor_u; // message handler + c3_l coq_l; // connection number + c3_o liv_o; // connection live + struct _u3_shan* san_u; // server backpointer +} u3_chan; + +/* u3_shan: ipc port server. +*/ +typedef struct _u3_shan { + uv_pipe_t pyp_u; // server stream handler + c3_l nex_l; // next connection number + struct _u3_port* gen_u; // port backpointer + struct _u3_chan* can_u; // connection list +} u3_shan; + + +/* u3_port: description of an IPC port +*/ +typedef struct _u3_port { + c3_c* nam_c; // name of port + c3_o con_o; + struct _u3_shan* san_u; // server reference + struct _u3_lick* lic_u; // device backpointer + struct _u3_port* nex_u; // next pointer +} u3_port; + +/* u3_lick: a list of devices +*/ +typedef struct _u3_lick { + u3_auto car_u; // driver + c3_c* fod_c; // IPC folder location + u3_cue_xeno* sil_u; // cue handle + struct _u3_port* gen_u; // port list +} u3_lick; + +static const c3_c URB_DEV_PATH[] = "/.urb/dev"; + +/* _lick_string_to_knot(): convert c unix path component to $knot +*/ +static u3_atom +_lick_string_to_knot(c3_c* pax_c) +{ + u3_assert(pax_c); + u3_assert(!strchr(pax_c, '/')); + if ( '!' == *pax_c ) { + pax_c++; + } + return u3i_string(pax_c); +} + +/* _lick_string_to_path(): convert c string to u3_noun $path +** +** c string must begin with the pier path plus mountpoint +*/ +static u3_noun +_lick_string_to_path(c3_c* pax_c) +{ + u3_noun not; + + //u3_assert(pax_c[-1] == '/'); + c3_c* end_c = strchr(pax_c, '/'); + if ( !end_c ) { + return u3nc(_lick_string_to_knot(pax_c), u3_nul); + } + else { + *end_c = 0; + not = _lick_string_to_knot(pax_c); + *end_c = '/'; + return u3nc(not, _lick_string_to_path(end_c + 1)); + } +} + +/* _lick_it_path(): path for ipc files +*/ +static c3_c* +_lick_it_path(u3_noun pax) +{ + c3_w len_w = 0; + c3_c *pas_c; + + // measure + // + { + u3_noun wiz = pax; + + while ( u3_nul != wiz ) { + len_w += (1 + u3r_met(3, u3h(wiz))); + wiz = u3t(wiz); + } + } + + // cut + // + pas_c = c3_malloc(len_w + 1); + pas_c[len_w] = '\0'; + { + u3_noun wiz = pax; + c3_c* waq_c = pas_c; + + while ( u3_nul != wiz ) { + c3_w tis_w = u3r_met(3, u3h(wiz)); + + if ( (u3_nul == u3t(wiz)) ) { + *waq_c++ = '/'; + } else *waq_c++ = '/'; + + u3r_bytes(0, tis_w, (c3_y*)waq_c, u3h(wiz)); + waq_c += tis_w; + + wiz = u3t(wiz); + } + *waq_c = 0; + } + u3z(pax); + return pas_c; +} + +/* _lick_send_noun(): jam and send noun over chan. +*/ +static void +_lick_send_noun(u3_chan* can_u, u3_noun nun) +{ + c3_y* byt_y; + c3_d len_d; + + u3s_jam_xeno(nun, &len_d, &byt_y); + u3z(nun); + u3_newt_send((u3_mojo*)&can_u->mor_u, len_d, byt_y); +} + +/* _lick_mote_free(): u3_moat-shaped close callback. +*/ +static void +_lick_moat_free(void* ptr_v, ssize_t err_i, const c3_c* err_c) +{ + c3_free((u3_chan*)ptr_v); +} + +/* _lick_close_cb(): socket close callback. +*/ +static void +_lick_close_cb(uv_handle_t* had_u) +{ + c3_free((u3_shan*)had_u); +} + +/* _lick_moor_poke(): called on message read from u3_moor. +*/ +static void +_lick_moor_poke(void* ptr_v, c3_d len_d, c3_y* byt_y) +{ + u3_weak put; + u3_noun dev, nam, dat, wir, cad; + + u3_chan* can_u = (u3_chan*)ptr_v; + u3_port* gen_u = can_u->san_u->gen_u; + u3_lick* lic_u = gen_u->lic_u; + c3_i err_i = 0; + c3_c* err_c; + c3_c* tag_c; + c3_c* rid_c; + + put = u3s_cue_xeno_with(lic_u->sil_u, len_d, byt_y); + if ( u3_none == put ) { + can_u->mor_u.bal_f(can_u, -1, "cue-none"); + return; + } + if ( c3n == u3r_cell(put, &nam, &dat) ) { + can_u->mor_u.bal_f(can_u, -2, "put-bad"); + u3z(put); + return; + } + + wir = u3nc(c3__lick, u3_nul); + dev = _lick_string_to_path(gen_u->nam_c+1); + cad = u3nt(c3__soak, dev, put); + u3_auto_peer( + u3_auto_plan(&lic_u->car_u, u3_ovum_init(0, c3__l, wir, cad)), + 0, 0, 0); +} + +/* _lick_close_chan(): close given channel, freeing. +*/ +static void +_lick_close_chan(u3_chan* can_u) +{ + u3_shan* san_u = can_u->san_u; + u3_lick* lic_u = san_u->gen_u->lic_u; + u3_port* gen_u = san_u->gen_u; + gen_u->con_o = c3n; + u3_chan* inn_u; + // remove chan from server's connection list. + // + if ( san_u->can_u == can_u ) { + san_u->can_u = (u3_chan*)can_u->mor_u.nex_u; + } + else { + for ( inn_u = san_u->can_u; inn_u; inn_u = (u3_chan*)inn_u->mor_u.nex_u ) { + if ( (u3_chan*)inn_u->mor_u.nex_u == can_u ) { + inn_u->mor_u.nex_u = can_u->mor_u.nex_u; + break; + } + } + } + can_u->mor_u.nex_u = NULL; + + if ( NULL == san_u->can_u ) { + // send a close event to arvo and stop reading. + // + u3_noun wir, cad, dev, dat, mar; + + wir = u3nc(c3__lick, u3_nul); + dev = _lick_string_to_path(gen_u->nam_c+1); + mar = u3i_string("disconnect"); + dat = u3_nul; + + cad = u3nq(c3__soak, dev, mar, dat); + + u3_auto_peer( + u3_auto_plan(&lic_u->car_u, + u3_ovum_init(0, c3__l, wir, cad)), + 0, 0, 0); + } + + u3_newt_moat_stop((u3_moat*)&can_u->mor_u, _lick_moat_free); +} + +/* _lick_moor_bail(): error callback for u3_moor. +*/ +static void +_lick_moor_bail(void* ptr_v, ssize_t err_i, const c3_c* err_c) +{ + u3_chan* can_u = (u3_chan*)ptr_v; + + if ( err_i != UV_EOF ) { + u3l_log("lick: moor bail %zd %s", err_i, err_c); + if ( _(can_u->liv_o) ) { + _lick_send_noun(can_u, u3nq(0, c3__bail, u3i_word(err_i), + u3i_string(err_c))); + can_u->liv_o = c3n; + } + } + _lick_close_chan(can_u); +} + +/* _lick_sock_cb(): socket connection callback. +*/ +static void +_lick_sock_cb(uv_stream_t* sem_u, c3_i tas_i) +{ + u3_shan* san_u = (u3_shan*)sem_u; + u3_port* gen_u = san_u->gen_u; + u3_chan* can_u; + c3_i err_i; + + can_u = c3_calloc(sizeof(u3_chan)); + can_u->mor_u.ptr_v = can_u; + can_u->mor_u.pok_f = _lick_moor_poke; + can_u->mor_u.bal_f = _lick_moor_bail; + can_u->coq_l = san_u->nex_l++; + can_u->san_u = san_u; + err_i = uv_timer_init(u3L, &can_u->mor_u.tim_u); + u3_assert(!err_i); + err_i = uv_pipe_init(u3L, &can_u->mor_u.pyp_u, 0); + u3_assert(!err_i); + err_i = uv_accept(sem_u, (uv_stream_t*)&can_u->mor_u.pyp_u); + u3_assert(!err_i); + u3_newt_read((u3_moat*)&can_u->mor_u); + can_u->mor_u.nex_u = (u3_moor*)san_u->can_u; + san_u->can_u = can_u; + gen_u->con_o = c3y; + + // only send on first connection + if ( NULL == can_u->mor_u.nex_u ) { + u3_noun dev, dat, wir, cad, mar; + wir = u3nc(c3__lick, u3_nul); + dev = _lick_string_to_path(gen_u->nam_c+1); + mar = u3i_string("connect"); + dat = u3_nul; + + cad = u3nq(c3__soak, dev, mar, dat); + u3_auto_peer( + u3_auto_plan(&gen_u->lic_u->car_u, u3_ovum_init(0, c3__l, wir, cad)), + 0, 0, 0); + } +} + +/* _lick_close_sock(): close an port's socket +*/ +static void +_lick_close_sock(u3_shan* san_u) +{ + u3_lick* lic_u = san_u->gen_u->lic_u; + c3_w len_w = strlen(lic_u->fod_c) + strlen(san_u->gen_u->nam_c) + 2; + c3_c* paf_c = c3_malloc(len_w); + c3_i wit_i; + wit_i = snprintf(paf_c, len_w, "%s/%s", lic_u->fod_c, san_u->gen_u->nam_c); + + u3_assert(wit_i > 0); + u3_assert(len_w == (c3_w)wit_i + 1); + + if ( 0 != unlink(paf_c) ) { + if ( ENOENT != errno ) { + u3l_log("lick: failed to unlink socket: %s", uv_strerror(errno)); + } + } + + uv_close((uv_handle_t*)&san_u->pyp_u, _lick_close_cb); + c3_free(paf_c); +} + +/* _lick_mkdirp(): recursive mkdir of dirname of pax_c. +*/ +static c3_o +_lick_mkdirp(c3_c* por_c) +{ + c3_c pax_c[2048]; + + strncpy(pax_c, por_c, sizeof(pax_c)); + + c3_c* fas_c = strchr(pax_c + 1, '/'); + + while ( fas_c ) { + *fas_c = 0; + if ( 0 != mkdir(pax_c, 0777) && EEXIST != errno ) { + return c3n; + } + *fas_c++ = '/'; + fas_c = strchr(fas_c, '/'); + } + return c3y; +} + +/* _lick_init_sock(): initialize socket device. +*/ +static void +_lick_init_sock(u3_shan* san_u) +{ + // the full socket path is limited to about 108 characters, + // and we want it to be relative to the pier. save our current + // path, chdir to the pier, open the socket at the desired + // path, then chdir back. hopefully there aren't any threads. + // + c3_c pax_c[2048]; + c3_i err_i; + c3_c por_c[2048] = "."; + u3_port* gen_u = san_u->gen_u; + + if ( NULL == getcwd(pax_c, sizeof(pax_c)) ) { + u3l_log("lick: getcwd: %s", uv_strerror(errno)); + u3_king_bail(); + } + if ( 0 != chdir(u3_Host.dir_c) ) { + u3l_log("lick: chdir: %s", uv_strerror(errno)); + u3_king_bail(); + } + + strcat(por_c, URB_DEV_PATH); + strcat(por_c, gen_u->nam_c); + + if ( c3y != _lick_mkdirp(por_c) ) { + u3l_log("lick: mkdir %s: %s", por_c, strerror(errno)); + goto _lick_sock_err_chdir; + } + + if ( 0 != unlink(por_c) && errno != ENOENT ) { + u3l_log("lick: unlink: %s", uv_strerror(errno)); + goto _lick_sock_err_chdir; + } + if ( 0 != (err_i = uv_pipe_init(u3L, &san_u->pyp_u, 0)) ) { + u3l_log("lick: uv_pipe_init: %s", uv_strerror(err_i)); + goto _lick_sock_err_chdir; + } + + if ( 0 != (err_i = uv_pipe_bind(&san_u->pyp_u, por_c)) ) { + u3l_log("lick: uv_pipe_bind: %s", uv_strerror(err_i)); + u3l_log("lick: uv_pipe_bind: %s", por_c); + goto _lick_sock_err_chdir; + } + if ( 0 != (err_i = uv_listen((uv_stream_t*)&san_u->pyp_u, 0, + _lick_sock_cb)) ) { + u3l_log("lick: uv_listen: %s", uv_strerror(err_i)); + goto _lick_sock_err_unlink; + } + if ( 0 != chdir(pax_c) ) { + u3l_log("lick: chdir: %s", uv_strerror(errno)); + goto _lick_sock_err_close; + } + return; + +_lick_sock_err_close: + uv_close((uv_handle_t*)&san_u->pyp_u, _lick_close_cb); +_lick_sock_err_unlink: + if ( 0 != unlink(gen_u->nam_c) ) { + u3l_log("lick: unlink: %s", uv_strerror(errno)); + } +_lick_sock_err_chdir: + if ( 0 != chdir(pax_c) ) { + u3l_log("lick: chdir: %s", uv_strerror(errno)); + } + u3_king_bail(); +} + +/* u3_lick_ef_shut(): Close an IPC port +*/ +static void +_lick_ef_shut(u3_lick* lic_u, u3_noun nam) +{ + c3_c* nam_c = _lick_it_path(nam); + + u3_port* cur_u = lic_u->gen_u; + u3_port* las_u = NULL; + + while ( NULL != cur_u ) { + if ( 0 == strcmp(cur_u->nam_c, nam_c) ) { + _lick_close_sock(cur_u->san_u); + if( las_u == NULL ) { + lic_u->gen_u = cur_u->nex_u; + } + else { + las_u->nex_u = cur_u->nex_u; + } + c3_free(cur_u); + return; + } + las_u = cur_u; + cur_u = cur_u->nex_u; + } + // XX We should delete empty folders in the pier/.urb/dev path +} + + +/* u3_lick_ef_spin(): Open an IPC port +*/ +static void +_lick_ef_spin(u3_lick* lic_u, u3_noun nam) +{ + c3_c* nam_c = _lick_it_path(nam); + u3_port* las_u = lic_u->gen_u; + + while ( NULL != las_u ) { + if( 0 == strcmp(las_u->nam_c, nam_c) ) { + c3_free(nam_c); + return; + } + las_u = las_u->nex_u; + } + u3_port* gen_u = c3_calloc(sizeof(*gen_u)); + gen_u->san_u = c3_calloc(sizeof(*gen_u->san_u)); + + gen_u->lic_u = lic_u; + gen_u->san_u->gen_u = gen_u; + gen_u->nam_c = nam_c; + gen_u->con_o = c3n; + + _lick_init_sock(gen_u->san_u); + if ( NULL == las_u) { + lic_u->gen_u = gen_u; + } + else las_u->nex_u = gen_u; +} + +/* _lick_ef_spit(): spit effects to port +*/ +static void +_lick_ef_spit(u3_lick* lic_u, u3_noun nam, u3_noun dat) +{ + c3_c* nam_c = _lick_it_path(nam); + u3_port* gen_u = NULL; + u3_port* cur_u = lic_u->gen_u; + while (cur_u != NULL){ + if( 0 == strcmp(cur_u->nam_c, nam_c) ) { + gen_u = cur_u; + break; + } + cur_u = cur_u->nex_u; + } + if ( NULL == gen_u ) { + u3l_log("lick: spit: gen %s not found", nam_c); + u3z(dat); + return; + } + + if( c3y == gen_u->con_o ) { + _lick_send_noun(gen_u->san_u->can_u, dat); + } + else { + u3_noun dev, wir, cad, mar; + u3z(dat); + wir = u3nc(c3__lick, u3_nul); + dev = _lick_string_to_path(gen_u->nam_c+1); + mar = u3i_string("error"); + dat = u3i_string("not connected"); + cad = u3nq(c3__soak, dev, mar, dat); + u3_auto_peer( + u3_auto_plan(&gen_u->lic_u->car_u, u3_ovum_init(0, c3__l, wir, cad)), + 0, 0, 0); + } +} + + +/* _lick_io_kick(): apply effects. +*/ +static c3_o +_lick_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) +{ + u3_lick* lic_u = (u3_lick*)car_u; + + u3_noun tag, i_wir, par; + u3_noun nam, dat, tmp; + c3_o ret_o, dev_o; + + if ( (c3n == u3r_cell(wir, &i_wir, 0)) + || (c3n == u3r_cell(cad, &tag, &tmp)) + || (c3__lick != i_wir) ) + { + ret_o = c3n; + } + else { + if ( (c3__spin == tag) ) { + _lick_ef_spin(lic_u, u3k(tmp)); // execute spin command + ret_o = c3y; + } + else if ( (c3__shut == tag) ) { + _lick_ef_shut(lic_u, u3k(tmp)); // execute shut command + ret_o = c3y; + } + else if ( c3__spit == tag ) { + if ( c3y == u3r_cell(tmp, &nam, &dat) ) { + _lick_ef_spit(lic_u, u3k(nam), u3k(dat)); + } + ret_o = c3y; + } + else { + ret_o = c3n; + } + } + + u3z(wir); + u3z(cad); + return ret_o; +} + +/* _lick_born_news(): initialization complete on %born. +*/ +static void +_lick_born_news(u3_ovum* egg_u, u3_ovum_news new_e) +{ + u3_auto* car_u = egg_u->car_u; + + if ( u3_ovum_done == new_e ) { + car_u->liv_o = c3y; + } +} + +/* _lick_born_bail(): %born is essential, retry failures. +*/ +static void +_lick_born_bail(u3_ovum* egg_u, u3_noun lud) +{ + u3l_log("lick: %%born failure;"); + u3z(lud); + u3_ovum_free(egg_u); +} + +/* _lick_io_talk(): notify %lick that we're live + * pass it a list of device names +*/ +static void +_lick_io_talk(u3_auto* car_u) +{ + u3_lick* lic_u = (u3_lick*)car_u; + u3_noun wir = u3nc(c3__lick, u3_nul); + u3_noun cad = u3nc(c3__born, u3_nul); + + u3_auto_peer( + u3_auto_plan(car_u, u3_ovum_init(0, c3__l, wir, cad)), + 0, + _lick_born_news, + _lick_born_bail); + + car_u->liv_o = c3y; +} + +/* _lick_io_exit(): close all open device files and exit +*/ +static void +_lick_io_exit(u3_auto* car_u) +{ + u3_lick* lic_u = (u3_lick*)car_u; + u3_port* cur_u = lic_u->gen_u; + u3_port* nex_u; + while ( NULL != cur_u ) { + _lick_close_sock(cur_u->san_u); + nex_u = cur_u->nex_u; + c3_free(cur_u); + cur_u = nex_u; + } + + u3s_cue_xeno_done(lic_u->sil_u); + c3_free(lic_u); +} + + +/* u3_lick(): initialize hardware control vane. +*/ +u3_auto* +u3_lick_io_init(u3_pier* pir_u) +{ + u3_lick* lic_u = c3_calloc(sizeof(*lic_u)); + + c3_c pax_c[2048] = ""; + struct stat st = {0}; + strcat(pax_c, u3_Host.dir_c); + strcat(pax_c, URB_DEV_PATH); + + if ( -1 == stat(pax_c, &st) ) { + u3l_log("lick init mkdir %s",pax_c ); + if ( mkdir(pax_c, 0700) && (errno != EEXIST) ) { + u3l_log("lick cannot make directory"); + u3_king_bail(); + } + } + + lic_u->sil_u = u3s_cue_xeno_init(); + lic_u->fod_c = strdup(pax_c); + + u3_auto* car_u = &lic_u->car_u; + car_u->nam_m = c3__lick; + car_u->liv_o = c3n; + car_u->io.talk_f = _lick_io_talk; + car_u->io.kick_f = _lick_io_kick; + car_u->io.exit_f = _lick_io_exit; + + return car_u; +} diff --git a/pkg/vere/king.c b/pkg/vere/king.c index 03bfd32761..7446ae7199 100644 --- a/pkg/vere/king.c +++ b/pkg/vere/king.c @@ -366,6 +366,15 @@ u3_king_next(c3_c* pac_c, c3_c** out_c) ret_i = asprintf(&url_c, "%s/%s/%s/next", ver_hos_c, pac_c, URBIT_VERSION); u3_assert( ret_i > 0 ); + // no-op if pace is set to once + // + if ( 0 == strcmp(pac_c, "once") ) { + c3_free(url_c); + fprintf(stderr, "vere: pace is set to \"once\", skipping upgrade\r\n"); + fprintf(stderr, "vere: set pace to \"live\" and try again\r\n"); + return -1; + } + // skip printfs on failed requests (/next is usually not present) // if ( _king_curl_bytes(url_c, &len_w, &hun_y, 0) ) { diff --git a/pkg/vere/pier.c b/pkg/vere/pier.c index 263af55e1a..1e39d14ef4 100644 --- a/pkg/vere/pier.c +++ b/pkg/vere/pier.c @@ -3,6 +3,7 @@ #include "db/lmdb.h" #include "ent.h" #include "noun.h" +#include "pace.h" #include "vere.h" #include "version.h" @@ -674,8 +675,8 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) // XX organizing version constants // #define VERE_NAME "vere" -#define VERE_ZUSE 413 -#define VERE_LULL 324 +#define VERE_ZUSE 412 +#define VERE_LULL 323 /* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN */ @@ -807,12 +808,13 @@ _pier_wyrd_card(u3_pier* pir_u) // XX god_u not necessarily available yet, refactor call sites // - u3_noun ver = u3nt(u3i_string(VERE_NAME), + u3_noun ver = u3nq(u3i_string(VERE_NAME), + u3i_string(U3_VERE_PACE), u3dc("scot", c3__ta, u3i_string(URBIT_VERSION)), u3_nul); u3_noun kel = u3nl(u3nc(c3__zuse, VERE_ZUSE), // XX from both king and serf? u3nc(c3__lull, VERE_LULL), // XX from both king and serf? - u3nc(c3__arvo, 238), // XX from both king and serf? + u3nc(c3__arvo, 237), // XX from both king and serf? u3nc(c3__hoon, 139), // god_u->hon_y u3nc(c3__nock, 4), // god_u->noc_y u3_none); diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index 9561dedec1..cef16810b6 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -1231,6 +1231,13 @@ u3_auto* u3_behn_io_init(u3_pier* pir_u); + /** lick, IPC communication. + **/ + /* u3_lick_io_init(): initialize loch vane. + */ + u3_auto* + u3_lick_io_init(u3_pier* pir_u); + /** HTTP server. **/ /* u3_http_io_init(): initialize http I/O.