diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 39ddfe03e9..dca6750619 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -217,6 +217,15 @@ versioned_http_file( version = "721fa05", ) +versioned_http_archive( + name = "natpmp", + build_file = "//bazel/third_party/natpmp:natpmp.BUILD", + sha256 = "0684ed2c8406437e7519a1bd20ea83780db871b3a3a5d752311ba3e889dbfc70", + strip_prefix = "libnatpmp-{version}", + url = "http://miniupnp.free.fr/files/libnatpmp-{version}.tar.gz", + version = "20230423", +) + versioned_http_file( name = "solid_pill", sha256 = "8b658fcee6978e2b19004a54233cab953e77ea0bb6c3a04d1bfda4ddc6be63c5", diff --git a/bazel/third_party/natpmp/BUILD.bazel b/bazel/third_party/natpmp/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bazel/third_party/natpmp/natpmp.BUILD b/bazel/third_party/natpmp/natpmp.BUILD new file mode 100644 index 0000000000..b3a7edd7e0 --- /dev/null +++ b/bazel/third_party/natpmp/natpmp.BUILD @@ -0,0 +1,8 @@ +cc_library( + name = "natpmp", + srcs = ["natpmp.c", "getgateway.c"], + hdrs = ["natpmp.h", "getgateway.h", "natpmp_declspec.h"], + copts = ["-O3"], + linkstatic = True, + visibility = ["//visibility:public"], +) diff --git a/pkg/noun/nock.c b/pkg/noun/nock.c index 452b04c309..eb459d17f7 100644 --- a/pkg/noun/nock.c +++ b/pkg/noun/nock.c @@ -1400,7 +1400,7 @@ _n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o) case 9: u3x_cell(arg, &hed, &tel); - if ( (1 == hed) || (3 == u3qc_cap(hed)) ) { + if ( (1 == hed) || (3 == u3qc_cap(u3x_atom(hed))) ) { u3_noun mac = u3nq(7, u3k(tel), 2, u3nt(u3nc(0, 1), 0, u3k(hed))); tot_w += _n_comp(ops, mac, los_o, tel_o); u3z(mac); diff --git a/pkg/vere/BUILD.bazel b/pkg/vere/BUILD.bazel index e736d0e8e1..6303b87201 100644 --- a/pkg/vere/BUILD.bazel +++ b/pkg/vere/BUILD.bazel @@ -140,6 +140,7 @@ vere_library( "@lmdb", "@openssl", "@uv", + "@natpmp", ] + select({ "@platforms//os:macos": [], "@platforms//os:linux": [ diff --git a/pkg/vere/disk.c b/pkg/vere/disk.c index 18fdf31fec..58cb2f822f 100644 --- a/pkg/vere/disk.c +++ b/pkg/vere/disk.c @@ -31,15 +31,6 @@ struct _u3_disk_walk { c3_o liv_o; }; -// for u3_lmdb_init() calls -static const size_t siz_i = -#if (defined(U3_CPU_aarch64) && defined(U3_OS_linux)) - // 500 GiB is as large as musl on aarch64 wants to allow - 0x7d00000000; -#else - 0x10000000000; -#endif - #undef VERBOSE_DISK #undef DISK_TRACE_JAM #undef DISK_TRACE_CUE @@ -680,7 +671,7 @@ u3_disk_save_meta_meta(c3_c* log_c, { MDB_env* dbm_u; - if ( 0 == (dbm_u = u3_lmdb_init(log_c, siz_i)) ) { + if ( 0 == (dbm_u = u3_lmdb_init(log_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize meta-lmdb\r\n"); return c3n; } @@ -1240,7 +1231,7 @@ _disk_epoc_roll(u3_disk* log_u, c3_d epo_d) log_u->mdb_u = 0; // initialize db of new epoch - if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, siz_i)) ) { + if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize database\r\n"); c3_free(log_u); goto fail3; @@ -1499,7 +1490,7 @@ _disk_migrate(u3_disk* log_u, c3_d eve_d) return c3n; } - if ( 0 == (log_u->mdb_u = u3_lmdb_init(tmp_c, siz_i)) ) { + if ( 0 == (log_u->mdb_u = u3_lmdb_init(tmp_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize database at %s\r\n", tmp_c); return c3n; @@ -1533,7 +1524,7 @@ _disk_migrate(u3_disk* log_u, c3_d eve_d) strerror(errno)); } - if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, siz_i)) ) { + if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize database at %s\r\n", epo_c); return c3n; @@ -1632,7 +1623,9 @@ u3_disk_chop(u3_disk* log_u, c3_d eve_d) u3_disk_epoc_list(log_u, sot_d); if ( len_z <= 2 ) { - fprintf(stderr, "chop: nothing to do, have a great day\r\n"); + fprintf(stderr, "chop: nothing to do, try running roll first\r\n" + "chop: for more info see " + "https://docs.urbit.org/manual/running/vere#chop\r\n"); exit(0); // enjoy } @@ -1734,7 +1727,7 @@ _disk_epoc_load(u3_disk* log_u, c3_d lat_d) snprintf(epo_c, 8192, "%s/0i%" PRIc3_d, log_u->com_u->pax_c, lat_d); // initialize latest epoch's db - if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, siz_i)) ) { + if ( 0 == (log_u->mdb_u = u3_lmdb_init(epo_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize database at %s\r\n", epo_c); return _epoc_fail; @@ -1878,7 +1871,7 @@ u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u) if ( c3y == exs_o ) { // load the old data.mdb file - if ( 0 == (log_u->mdb_u = u3_lmdb_init(log_c, siz_i)) ) { + if ( 0 == (log_u->mdb_u = u3_lmdb_init(log_c, u3_Host.ops_u.siz_i)) ) { fprintf(stderr, "disk: failed to initialize lmdb\r\n"); c3_free(log_u); return 0; diff --git a/pkg/vere/io/ames.c b/pkg/vere/io/ames.c index 496d439b80..66589f6aa5 100644 --- a/pkg/vere/io/ames.c +++ b/pkg/vere/io/ames.c @@ -7,6 +7,7 @@ #include "ur.h" #include "zlib.h" +#include "natpmp.h" #include @@ -74,6 +75,11 @@ typedef enum u3_stun_state { u3_lane sef_u; // our lane, if we know it c3_o wok_o; // STUN worked, set on first success } sun_u; // + struct { + natpmp_t req_u; // libnatpmp struct for mapping request + uv_poll_t pol_u; // handle waits on libnatpmp socket + uv_timer_t tim_u; // every two hours if mapping succeeds + } nat_u; // libnatpmp stuff for port forwarding c3_o nal_o; // lane cache backcompat flag struct { // config: c3_o net_o; // can send @@ -2473,6 +2479,69 @@ _ames_recv_cb(uv_udp_t* wax_u, } } +static void natpmp_init(uv_timer_t* handle); + +static void +natpmp_cb(uv_poll_t* handle, + c3_i status, + c3_i events) +{ + + if (status != 0) { + return; + } + + u3_ames* sam_u = handle->data; + + natpmpresp_t response; + c3_i err_i = readnatpmpresponseorretry(&sam_u->nat_u.req_u, &response); + if ( NATPMP_TRYAGAIN == err_i ) { + return; + } + + uv_poll_stop(handle); + + if ( 0 != err_i ) { + u3l_log("ames: natpmp error %i", err_i); + uv_poll_stop(&sam_u->nat_u.pol_u); + closenatpmp(&sam_u->nat_u.req_u); + return; + } + + u3l_log("ames: mapped public port %hu to localport %hu lifetime %u", + response.pnu.newportmapping.mappedpublicport, + response.pnu.newportmapping.privateport, + response.pnu.newportmapping.lifetime); + + closenatpmp(&sam_u->nat_u.req_u); + sam_u->nat_u.tim_u.data = sam_u; + uv_timer_start(&sam_u->nat_u.tim_u, natpmp_init, 7200000, 0); +} + +static void +natpmp_init(uv_timer_t *handle) +{ + u3_ames* sam_u = handle->data; + c3_s por_s = sam_u->pir_u->por_s; + + c3_i err_i = initnatpmp(&sam_u->nat_u.req_u, 0, 0); + + if (err_i != 0) { + return; + } + + err_i = uv_poll_init(u3L, &sam_u->nat_u.pol_u, sam_u->nat_u.req_u.s); + + if (err_i != 0) { + return; + } + + sendnewportmappingrequest(&sam_u->nat_u.req_u, NATPMP_PROTOCOL_UDP, por_s, por_s, 7200); + + sam_u->nat_u.pol_u.data = sam_u; + uv_poll_start(&sam_u->nat_u.pol_u, UV_READABLE, natpmp_cb); +} + static void _mdns_dear_bail(u3_ovum* egg_u, u3_noun lud) { @@ -2593,6 +2662,11 @@ _ames_io_start(u3_ames* sam_u) u3z(our); mdns_init(por_s, !sam_u->pir_u->fak_o, our_s, _ames_put_dear, (void *)sam_u); + + if ( c3n == sam_u->pir_u->fak_o ) { + uv_timer_start(&sam_u->nat_u.tim_u, natpmp_init, 0, 0); + } + c3_free(our_s); } @@ -2977,6 +3051,12 @@ _ames_io_exit(u3_auto* car_u) u3_ames* sam_u = (u3_ames*)car_u; uv_close(&sam_u->had_u, _ames_exit_cb); uv_close((uv_handle_t*)&sam_u->sun_u.tim_u, 0); + uv_close((uv_handle_t*)&sam_u->nat_u.tim_u, 0); + + uv_handle_type handle = uv_handle_get_type((uv_handle_t *)&sam_u->nat_u.pol_u); + if ( UV_UNKNOWN_HANDLE != handle) { + uv_close((uv_handle_t*)&sam_u->nat_u.pol_u, 0); + } } /* _ames_io_info(): produce status info. @@ -3084,6 +3164,10 @@ u3_ames_io_init(u3_pier* pir_u) uv_timer_init(u3L, &sam_u->sun_u.tim_u); sam_u->sun_u.tim_u.data = sam_u; + // initialize libnatpmp + sam_u->nat_u.tim_u.data = sam_u; + uv_timer_init(u3L, &sam_u->nat_u.tim_u); + // enable forwarding on galaxies only u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); u3_noun rac = u3do("clan:title", who); diff --git a/pkg/vere/main.c b/pkg/vere/main.c index 2222f87dd1..33fd36290a 100644 --- a/pkg/vere/main.c +++ b/pkg/vere/main.c @@ -18,6 +18,8 @@ #include "db/lmdb.h" #include "getopt.h" #include "libgen.h" +#include "pthread.h" +#include "spawn.h" #include "ca_bundle.h" #include "pace.h" @@ -193,6 +195,14 @@ _main_init(void) u3_Host.ops_u.lut_y = 31; /* aka 2G */ u3_Host.ops_u.lom_y = 31; + u3_Host.ops_u.siz_i = +#if (defined(U3_CPU_aarch64) && defined(U3_OS_linux)) + // 500 GiB is as large as musl on aarch64 wants to allow + 0x7d00000000; +#else + 0x10000000000; +#endif + u3C.eph_c = 0; u3C.tos_w = 0; } @@ -291,12 +301,14 @@ _main_getopt(c3_i argc, c3_c** argv) { "prop-url", required_argument, NULL, 2 }, { "prop-name", required_argument, NULL, 3 }, // - { "urth-loom", required_argument, NULL, 5 }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, - { "toss", required_argument, NULL, 9 }, + { "urth-loom", required_argument, NULL, 5 }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "toss", required_argument, NULL, 9 }, { "behn-allow-blocked", no_argument, NULL, 10 }, + { "serf-bin", required_argument, NULL, 11 }, + { "lmdb-map-size", required_argument, NULL, 12 }, // { NULL, 0, NULL, 0 }, }; @@ -340,6 +352,17 @@ _main_getopt(c3_i argc, c3_c** argv) u3_Host.ops_u.beb = c3y; break; } + case 11: { // serf-bin + u3_Host.wrk_c = strdup(optarg); + break; + } + case 12: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + return c3n; + } + + break; + } // special args // case c3__loom: { @@ -1569,10 +1592,11 @@ _cw_info(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "lmdb-map-size", required_argument, NULL, 9 }, { NULL, 0, NULL, 0 } }; @@ -1603,6 +1627,13 @@ _cw_info(c3_i argc, c3_c* argv[]) break; } + case 9: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case '?': { fprintf(stderr, "invalid argument\r\n"); exit(1); @@ -1744,10 +1775,11 @@ _cw_cram(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "lmdb-map-size", required_argument, NULL, 9 }, { NULL, 0, NULL, 0 } }; @@ -1778,6 +1810,13 @@ _cw_cram(c3_i argc, c3_c* argv[]) break; } + case 9: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case '?': { fprintf(stderr, "invalid argument\r\n"); exit(1); @@ -1840,11 +1879,12 @@ _cw_queu(c3_i argc, c3_c* argv[]) c3_c* roc_c = 0; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, - { "replay-from", required_argument, NULL, 'r' }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "lmdb-map-size", required_argument, NULL, 9 }, + { "replay-from", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } }; @@ -1875,6 +1915,13 @@ _cw_queu(c3_i argc, c3_c* argv[]) break; } + case 9: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case 'r': { roc_c = strdup(optarg); } break; @@ -1948,11 +1995,12 @@ _cw_meld(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, - { "gc-early", no_argument, NULL, 9 }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "gc-early", no_argument, NULL, 9 }, + { "lmdb-map-size", required_argument, NULL, 10 }, { NULL, 0, NULL, 0 } }; @@ -1988,6 +2036,13 @@ _cw_meld(c3_i argc, c3_c* argv[]) break; } + case 10: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case '?': { fprintf(stderr, "invalid argument\r\n"); exit(1); @@ -2116,11 +2171,12 @@ _cw_pack(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, - { "gc-early", no_argument, NULL, 9 }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "gc-early", no_argument, NULL, 9 }, + { "lmdb-map-size", required_argument, NULL, 10 }, { NULL, 0, NULL, 0 } }; @@ -2156,6 +2212,13 @@ _cw_pack(c3_i argc, c3_c* argv[]) break; } + case 10: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case '?': { fprintf(stderr, "invalid argument\r\n"); exit(1); @@ -2315,6 +2378,113 @@ _cw_play_impl(c3_d eve_d, c3_d sap_d, c3_o mel_o, c3_o sof_o, c3_o ful_o) return pay_d; } +/* _cw_play_fork_heed(): wait for EOF on STDIN or until canceled. +*/ +void* _cw_play_fork_heed(void* arg) { + c3_c buf[1]; + c3_zs red; + + do { + pthread_testcancel(); + red = read(STDIN_FILENO, buf, sizeof(buf)); + if ( 0 == red ) { + fprintf(stderr, "play: god save the king! committing sudoku...\r\n"); + exit(1); + } + } while ( 0 < red ); + + return NULL; +} + +/* _cw_play_fork(): spawn a subprocess for event replay. +*/ +static c3_i +_cw_play_fork(c3_d eve_d, c3_d sap_d, c3_o mel_o, c3_o sof_o, c3_o ful_o) +{ + // prepare args + // + c3_c eve_c[21], sap_c[21] = { 0 }; + if ( 0 > sprintf(eve_c, "%" PRIu64, eve_d) || + 0 > sprintf(sap_c, "%" PRIu64, sap_d) ) + { + fprintf(stderr, "play: error parsing args\r\n"); + return 1; + } + + c3_c *argv[11] = { + u3_Host.wrk_c, + "play", + u3_Host.dir_c, + "--replay-to", + eve_c, + "--snap-at", + sap_c, + }; + + c3_z i = 7; + if _(mel_o) { + argv[i++] = "--auto-meld"; + } + if _(sof_o) { + argv[i++] = "--soft-mugs"; + } + if _(ful_o) { + argv[i++] = "--full"; + } + argv[i] = NULL; + + // prepare a pipe for ipc with the subprocess + // + c3_i pipefd[2]; + if ( 0 != pipe(pipefd) ) { + fprintf(stderr, "play: failed to open pipe\r\n"); + return 1; + } + + // set the child process' stdin to read from the pipe + // + posix_spawn_file_actions_t action; + posix_spawn_file_actions_init(&action); + posix_spawn_file_actions_addclose(&action, pipefd[1]); + posix_spawn_file_actions_adddup2(&action, pipefd[0], STDIN_FILENO); + + // spawn a new serf process and call its play subcommand + // + pid_t pid; + if ( 0 != posix_spawn(&pid, u3_Host.wrk_c, &action, 0, argv, 0) ) { + fprintf(stderr, "play: posix_spawn: %d\r\n", errno); + return 1; + } + + // close the read end of the pipe in the parent + // + close(pipefd[0]); + + // wait for the child to exit + // + c3_i sat_i; + if ( -1 == waitpid(pid, &sat_i, 0) ) { + fprintf(stderr, "play: waitpid: %d\r\n", errno); + return 1; + } + + if ( WIFEXITED(sat_i) ) { + c3_i ret_i = WEXITSTATUS(sat_i); + if ( 0 != ret_i ) { + fprintf(stderr, "play: exited with %d\r\n", ret_i); + } + return ret_i; + } + else if ( WIFSIGNALED(sat_i) ) { + fprintf(stderr, "play: terminated by signal %d\r\n", WTERMSIG(sat_i)); + return 1; + } + else { + fprintf(stderr, "play: strange termination\r\n"); + return 1; + } +} + /* _cw_play(): replay events, but better. */ static void @@ -2407,9 +2577,14 @@ _cw_play(c3_i argc, c3_c* argv[]) exit(1); } + pthread_t ted; + pthread_create(&ted, NULL, _cw_play_fork_heed, NULL); + if ( !_cw_play_impl(eve_d, sap_d, mel_o, sof_o, ful_o) ) { fprintf(stderr, "mars: nothing to do!\r\n"); } + + pthread_cancel(ted); } /* _cw_prep(): prepare for upgrade @@ -2497,10 +2672,11 @@ _cw_chop(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { "no-demand", no_argument, NULL, 6 }, - { "swap", no_argument, NULL, 7 }, - { "swap-to", required_argument, NULL, 8 }, + { "loom", required_argument, NULL, c3__loom }, + { "no-demand", no_argument, NULL, 6 }, + { "swap", no_argument, NULL, 7 }, + { "swap-to", required_argument, NULL, 8 }, + { "lmdb-map-size", required_argument, NULL, 9 }, { NULL, 0, NULL, 0 } }; @@ -2531,6 +2707,13 @@ _cw_chop(c3_i argc, c3_c* argv[]) break; } + case 9: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case '?': { fprintf(stderr, "invalid argument\r\n"); exit(1); @@ -2578,7 +2761,8 @@ _cw_roll(c3_i argc, c3_c* argv[]) c3_w arg_w; static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, + { "loom", required_argument, NULL, c3__loom }, + { "lmdb-map-size", required_argument, NULL, 6 }, { NULL, 0, NULL, 0 } }; @@ -2586,6 +2770,13 @@ _cw_roll(c3_i argc, c3_c* argv[]) while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { switch ( ch_i ) { + case 6: { // lmdb-map-size + if ( 1 != sscanf(optarg, "%" SCNuMAX, &u3_Host.ops_u.siz_i) ) { + exit(1); + } + break; + } + case c3__loom: { if (_main_readw_loom("loom", &u3_Host.ops_u.lom_y)) { exit(1); @@ -2966,8 +3157,6 @@ main(c3_i argc, _main_self_path(); - // XX add argument - // if ( !u3_Host.wrk_c ) { u3_Host.wrk_c = bin_c; } @@ -3110,7 +3299,12 @@ main(c3_i argc, // we need the current snapshot's latest event number to // validate whether we can execute disk migration if ( u3_Host.ops_u.nuu == c3n ) { - _cw_play_impl(0, 0, c3n, c3n, c3n); + c3_i sat_i = _cw_play_fork(0, 0, c3n, c3n, c3n); + if ( sat_i ) { + fprintf(stderr, "play: replay failed: %d\r\n", sat_i); + exit(sat_i); + } + signal(SIGTSTP, _stop_exit); // XX unmap loom, else parts of the snapshot could be left in memory } diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index f97a76f142..b26ad4b27e 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -320,6 +320,7 @@ u3_even* vex_u; // --prop-*, boot enhancements c3_o beb; // --behn-allow-blocked + c3_z siz_i; // --lmdb-map-size } u3_opts; /* u3_host: entire host.