shrub/vere/main.c

576 lines
13 KiB
C
Raw Normal View History

2013-09-29 00:21:18 +04:00
/* v/main.c
**
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <setjmp.h>
#include <signal.h>
#include <gmp.h>
#include <stdint.h>
#include <uv.h>
#include <sigsegv.h>
#include <curses.h>
#include <termios.h>
#include <term.h>
#include <dirent.h>
#include <openssl/ssl.h>
2013-09-29 00:21:18 +04:00
#define U3_GLOBAL
2013-09-29 00:21:18 +04:00
#define C3_GLOBAL
#include "all.h"
#include "vere/vere.h"
2013-09-29 00:21:18 +04:00
/* _main_readw(): parse a word from a string.
*/
2014-11-06 06:10:22 +03:00
static u3_noun
_main_readw(const c3_c* str_c, c3_w max_w, c3_w* out_w)
{
c3_c* end_c;
c3_w par_w = strtoul(str_c, &end_c, 0);
if ( *str_c != '\0' && *end_c == '\0' && par_w < max_w ) {
*out_w = par_w;
2014-11-05 04:18:47 +03:00
return c3y;
}
2014-11-05 04:18:47 +03:00
else return c3n;
}
2014-11-08 01:54:59 +03:00
static c3_c hostbuf[2048]; // kill me
2015-05-19 21:38:23 +03:00
/* _main_presig(): prefix optional sig.
*/
c3_c*
_main_presig(c3_c* txt_c)
{
c3_c* new_c = malloc(2 + strlen(txt_c));
if ( '~' == *txt_c ) {
strcpy(new_c, txt_c);
} else {
new_c[0] = '~';
strcpy(new_c + 1, txt_c);
}
return new_c;
}
2013-09-29 00:21:18 +04:00
/* _main_getopt(): extract option map from command line.
*/
2014-11-06 06:10:22 +03:00
static u3_noun
2013-09-29 00:21:18 +04:00
_main_getopt(c3_i argc, c3_c** argv)
{
c3_i ch_i;
c3_w arg_w;
2013-09-29 00:21:18 +04:00
2014-11-05 04:18:47 +03:00
u3_Host.ops_u.abo = c3n;
u3_Host.ops_u.bat = c3n;
u3_Host.ops_u.gab = c3n;
u3_Host.ops_u.loh = c3n;
u3_Host.ops_u.dem = c3n;
u3_Host.ops_u.fog = c3n;
u3_Host.ops_u.fak = c3n;
2015-10-27 00:03:14 +03:00
u3_Host.ops_u.tex = c3n;
2014-11-05 04:18:47 +03:00
u3_Host.ops_u.pro = c3n;
2014-12-01 03:06:08 +03:00
u3_Host.ops_u.dry = c3n;
2015-05-19 21:56:44 +03:00
u3_Host.ops_u.veb = c3n;
2015-05-20 03:04:08 +03:00
u3_Host.ops_u.qui = c3n;
2014-11-05 04:18:47 +03:00
u3_Host.ops_u.nuu = c3n;
u3_Host.ops_u.mem = c3n;
u3_Host.ops_u.rep = c3n;
2014-09-11 04:01:32 +04:00
u3_Host.ops_u.kno_w = DefaultKernel;
2013-09-29 00:21:18 +04:00
2016-10-24 21:56:44 +03:00
while ( (ch_i=getopt(argc, argv,"G:B:A:I:w:t:f:k:l:n:p:r:LabcdgqvxFMPDXR")) != -1 ) {
2013-09-29 00:21:18 +04:00
switch ( ch_i ) {
2014-07-30 21:53:30 +04:00
case 'M': {
2014-11-05 04:18:47 +03:00
u3_Host.ops_u.mem = c3y;
2014-07-30 21:53:30 +04:00
break;
}
2016-01-26 20:50:32 +03:00
case 'B': {
u3_Host.ops_u.pil_c = strdup(optarg);
break;
}
2016-10-24 21:56:44 +03:00
case 'G': {
u3_Host.ops_u.gen_c = strdup(optarg);
break;
}
case 'A': {
u3_Host.ops_u.arv_c = strdup(optarg);
break;
}
2014-01-15 23:59:08 +04:00
case 'I': {
2015-08-25 02:23:13 +03:00
u3_Host.ops_u.imp_c = _main_presig(optarg);
2014-01-15 23:59:08 +04:00
break;
}
2015-06-03 02:17:55 +03:00
case 'w': {
2015-05-19 21:38:23 +03:00
u3_Host.ops_u.who_c = _main_presig(optarg);
2015-06-06 05:29:05 +03:00
u3_Host.ops_u.nuu = c3y;
2015-06-03 02:17:55 +03:00
break;
}
case 't': {
u3_Host.ops_u.tic_c = _main_presig(optarg);
2015-05-19 21:38:23 +03:00
break;
}
2015-10-27 00:03:14 +03:00
case 'x': {
u3_Host.ops_u.tex = c3y;
break;
}
case 'X': {
2015-10-27 00:03:14 +03:00
u3_Host.ops_u.fog = c3y;
break;
}
2014-01-15 23:59:08 +04:00
case 'f': {
2014-11-05 04:18:47 +03:00
if ( c3n == _main_readw(optarg, 100, &u3_Host.ops_u.fuz_w) ) {
return c3n;
2013-09-29 00:21:18 +04:00
}
break;
}
2014-01-15 23:59:08 +04:00
case 'k': {
2014-11-05 04:18:47 +03:00
if ( c3n == _main_readw(optarg, 256, &u3_Host.ops_u.kno_w) ) {
return c3n;
}
break;
}
case 'l': {
2014-11-05 04:18:47 +03:00
if ( c3n == _main_readw(optarg, 65536, &arg_w) ) {
return c3n;
2014-09-11 04:01:32 +04:00
} else u3_Host.ops_u.rop_s = arg_w;
2014-01-17 22:12:42 +04:00
break;
}
2014-01-17 21:42:47 +04:00
case 'n': {
2014-09-11 04:01:32 +04:00
u3_Host.ops_u.nam_c = strdup(optarg);
2014-01-17 21:42:47 +04:00
break;
}
2014-01-15 21:16:50 +04:00
case 'p': {
2014-11-05 04:18:47 +03:00
if ( c3n == _main_readw(optarg, 65536, &arg_w) ) {
return c3n;
2014-09-11 04:01:32 +04:00
} else u3_Host.ops_u.por_s = arg_w;
2014-01-15 21:16:50 +04:00
break;
}
case 'r': {
2014-09-11 04:01:32 +04:00
u3_Host.ops_u.raf_c = strdup(optarg);
break;
}
case 'R': {
u3_Host.ops_u.rep = c3y;
return c3y;
}
2014-11-05 04:18:47 +03:00
case 'L': { u3_Host.ops_u.loh = c3y; break; }
case 'F': {
2014-11-05 04:18:47 +03:00
u3_Host.ops_u.loh = c3y;
u3_Host.ops_u.fak = c3y;
break;
}
2014-11-05 04:18:47 +03:00
case 'a': { u3_Host.ops_u.abo = c3y; break; }
case 'b': { u3_Host.ops_u.bat = c3y; break; }
case 'c': { u3_Host.ops_u.nuu = c3y; break; }
case 'd': { u3_Host.ops_u.dem = c3y; break; }
case 'g': { u3_Host.ops_u.gab = c3y; break; }
2014-11-29 05:19:11 +03:00
case 'P': { u3_Host.ops_u.pro = c3y; break; }
2014-12-01 03:06:08 +03:00
case 'D': { u3_Host.ops_u.dry = c3y; break; }
2015-05-20 03:04:08 +03:00
case 'q': { u3_Host.ops_u.qui = c3y; break; }
2014-11-05 04:18:47 +03:00
case 'v': { u3_Host.ops_u.veb = c3y; break; }
2013-09-29 00:21:18 +04:00
case '?': default: {
2014-11-05 04:18:47 +03:00
return c3n;
2013-09-29 00:21:18 +04:00
}
}
}
if ( u3_Host.ops_u.arv_c != 0 && ( u3_Host.ops_u.imp_c == 0 ||
u3_Host.ops_u.nuu == c3n ) ) {
2016-10-25 03:23:43 +03:00
fprintf(stderr, "-A only makes sense when creating a new galaxy\n");
return c3n;
}
if ( u3_Host.ops_u.imp_c != 0 &&
u3_Host.ops_u.arv_c == 0 &&
u3_Host.ops_u.nuu == c3y ) {
fprintf(stderr, "can't create a new galaxy without specifying "
"the initial sync path with -A\n");
return c3n;
}
2016-10-24 21:56:44 +03:00
if ( u3_Host.ops_u.gen_c != 0 && ( u3_Host.ops_u.imp_c == 0 ||
u3_Host.ops_u.nuu == c3n ) ) {
2016-10-25 03:23:43 +03:00
fprintf(stderr, "-G only makes sense when creating a new galaxy\n");
2016-10-24 21:56:44 +03:00
return c3n;
}
if ( u3_Host.ops_u.tic_c != 0 && ( u3_Host.ops_u.imp_c != 0 ||
2016-10-25 03:23:43 +03:00
u3_Host.ops_u.nuu == c3n ) ) {
fprintf(stderr, "-t only makes sense when creating a new non-galaxy\n");
2016-10-24 21:56:44 +03:00
return c3n;
}
2014-09-11 04:01:32 +04:00
if ( u3_Host.ops_u.rop_s == 0 && u3_Host.ops_u.raf_c != 0 ) {
fprintf(stderr, "The -r flag requires -l.\n");
2014-11-05 04:18:47 +03:00
return c3n;
}
2015-09-28 02:00:17 +03:00
if ( u3_Host.ops_u.tic_c == 0 && u3_Host.ops_u.who_c != 0 ) {
c3_c tic_c[29];
printf("your ticket: ~");
scanf("%28s",tic_c);
u3_Host.ops_u.tic_c = _main_presig(tic_c);
}
2014-11-05 04:18:47 +03:00
if ( c3y == u3_Host.ops_u.bat ) {
u3_Host.ops_u.dem = c3y;
u3_Host.ops_u.nuu = c3y;
2014-01-16 05:41:30 +04:00
}
2016-01-27 00:31:26 +03:00
if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.pil_c != 0) {
2016-01-26 20:50:32 +03:00
fprintf(stderr, "-B only makes sense when bootstrapping a new instance\n");
return c3n;
}
2013-09-29 00:21:18 +04:00
2016-01-27 00:36:22 +03:00
if ( u3_Host.ops_u.pil_c != 0 ) {
struct stat s;
if ( stat(u3_Host.ops_u.pil_c, &s) != 0 ) {
fprintf(stderr, "pill %s not found\n", u3_Host.ops_u.pil_c);
return c3n;
}
}
2014-09-11 04:01:32 +04:00
if ( u3_Host.ops_u.nam_c == 0 ) {
u3_Host.ops_u.nam_c = getenv("HOSTNAME");
if ( u3_Host.ops_u.nam_c == 0 ) {
2014-01-17 21:42:47 +04:00
c3_w len_w = sysconf(_SC_HOST_NAME_MAX) + 1;
2014-11-08 01:54:59 +03:00
u3_Host.ops_u.nam_c = hostbuf;
2014-09-11 04:01:32 +04:00
if ( 0 != gethostname(u3_Host.ops_u.nam_c, len_w) ) {
2014-01-17 21:42:47 +04:00
perror("gethostname");
exit(1);
}
}
}
2014-04-16 07:28:22 +04:00
if ( argc != (optind + 1) && u3_Host.ops_u.who_c != 0 ) {
u3_Host.dir_c = strdup(1 + u3_Host.ops_u.who_c);
}
2013-09-29 00:21:18 +04:00
if ( argc != (optind + 1) ) {
2015-06-06 05:29:05 +03:00
return u3_Host.dir_c ? c3y : c3n;
} else {
2013-09-29 00:21:18 +04:00
{
c3_c* ash_c;
if ( (ash_c = strrchr(argv[optind], '/')) && (ash_c[1] == 0) ) {
*ash_c = 0;
}
}
2014-11-16 04:10:15 +03:00
u3_Host.dir_c = strdup(argv[optind]);
2014-11-05 04:18:47 +03:00
return c3y;
2013-09-29 00:21:18 +04:00
}
}
2014-09-11 04:01:32 +04:00
/* u3_ve_usage(): print usage and exit.
2013-09-29 00:21:18 +04:00
*/
static void
2014-09-11 04:01:32 +04:00
u3_ve_usage(c3_i argc, c3_c** argv)
2013-09-29 00:21:18 +04:00
{
2015-11-17 06:29:27 +03:00
#if 0
c3_c *use_c[] = {"Usage: %s [options...] computer\n",
2015-10-29 01:18:19 +03:00
"-c pier Create a new urbit in pier/\n",
"-w name Immediately upgrade to ~name\n",
"-t ticket Use ~ticket automatically\n",
"-I galaxy Start as ~galaxy\n",
2016-08-29 20:11:10 +03:00
"-A dir Use dir for initial galaxy sync\n",
"-F Fake keys\n",
"-L Local-only network\n",
2016-08-29 20:11:10 +03:00
"-B pill Bootstrap from this pill\n",
"-n host Set unix hostname\n",
"-p ames_port Set the HTTP port to bind to\n",
"-v Verbose\n",
2015-10-29 01:18:19 +03:00
"-q Quiet\n",
"-D Recompute from events\n",
"-P Profiling\n",
2015-10-29 01:18:19 +03:00
"-b Batch create\n",
"-d Daemon mode\n",
"-g Set GC flag\n",
"-x Exit immediately\n",
"-r host Initial peer address\n",
"-l port Initial peer port\n",
"-M Memory madness\n",
"-f Fuzz testing\n",
"-k stage Start at Hoon kernel version stage\n",
"-R Report urbit build info\n",
"-Xwtf Skip last event\n"};
2015-11-17 06:29:27 +03:00
#else
c3_c *use_c[] = {
"simple usage: \n",
" %s -c <mycomet> to create a comet (anonymous urbit)\n",
" %s -w <myplanet> -t <myticket> if you have a ticket\n",
" %s <myplanet or mycomet> to restart an existing urbit\n",
0
};
#endif
2015-10-08 20:17:15 +03:00
c3_i i;
2015-11-17 06:29:27 +03:00
for ( i=0; use_c[i]; i++ ) {
fprintf(stderr, use_c[i], argv[0]);
}
2013-09-29 00:21:18 +04:00
exit(1);
}
2014-09-11 04:01:32 +04:00
#if 0
/* u3_ve_panic(): panic and exit.
2013-09-29 00:21:18 +04:00
*/
static void
2014-09-11 04:01:32 +04:00
u3_ve_panic(c3_i argc, c3_c** argv)
2013-09-29 00:21:18 +04:00
{
fprintf(stderr, "%s: gross system failure\n", argv[0]);
exit(1);
}
2014-09-11 04:01:32 +04:00
#endif
2013-09-29 00:21:18 +04:00
2014-09-11 04:01:32 +04:00
/* u3_ve_sysopt(): apply option map to system state.
2013-09-29 00:21:18 +04:00
*/
static void
2014-09-11 04:01:32 +04:00
u3_ve_sysopt()
2013-09-29 00:21:18 +04:00
{
2014-11-16 04:10:15 +03:00
u3_Local = strdup(u3_Host.dir_c);
2013-09-29 00:21:18 +04:00
}
2014-09-11 04:01:32 +04:00
#if 0
2013-09-29 00:21:18 +04:00
static jmp_buf Signal_buf;
#ifndef SIGSTKSZ
# define SIGSTKSZ 16384
#endif
static uint8_t Sigstk[SIGSTKSZ];
volatile enum { sig_none, sig_overflow, sig_interrupt } Sigcause;
static void _main_cont(void *arg1, void *arg2, void *arg3)
{
(void)(arg1);
(void)(arg2);
(void)(arg3);
siglongjmp(Signal_buf, 1);
}
2013-09-29 00:21:18 +04:00
static void
overflow_handler(int emergency, stackoverflow_context_t scp)
{
if ( 1 == emergency ) {
write(2, "stack emergency\n", strlen("stack emergency" + 2));
exit(1);
} else {
Sigcause = sig_overflow;
sigsegv_leave_handler(_main_cont, NULL, NULL, NULL);
2013-09-29 00:21:18 +04:00
}
}
2014-10-10 05:27:02 +04:00
// Install signal handlers and set buffers.
//
// Note that we use the sigmask-restoring variant. Essentially, when
// we get a signal, we force the system back into the just-booted state.
// If anything goes wrong during boot (above), it's curtains.
{
if ( 0 != sigsetjmp(Signal_buf, 1) ) {
switch ( Sigcause ) {
case sig_overflow: printf("[stack overflow]\r\n"); break;
case sig_interrupt: printf("[interrupt]\r\n"); break;
default: printf("[signal error!]\r\n"); break;
}
Sigcause = sig_none;
signal(SIGINT, SIG_DFL);
stackoverflow_deinstall_handler();
// Print the trace, do a GC, etc.
//
// This is half-assed at present, so we exit.
//
u3_lo_sway(0, u3k(u3_wire_tax(u3_Wire)));
u3_lo_bail(u3A);
exit(1);
}
if ( -1 == stackoverflow_install_handler
(overflow_handler, Sigstk, SIGSTKSZ) )
{
fprintf(stderr, "overflow_handler: install failed\n");
exit(1);
}
signal(SIGINT, interrupt_handler);
signal(SIGIO, SIG_IGN);
}
2013-09-29 00:21:18 +04:00
static void
interrupt_handler(int x)
{
Sigcause = sig_interrupt;
longjmp(Signal_buf, 1);
}
2014-09-11 04:01:32 +04:00
#endif
2013-09-29 00:21:18 +04:00
2014-10-11 09:32:58 +04:00
#define GRAB
2014-10-10 05:27:02 +04:00
static void
report(void)
{
printf("---------\nLibraries\n---------\n");
printf("gmp: %s\n", gmp_version);
printf("sigsegv: %d.%d\n", (libsigsegv_version >> 8) & 0xff, libsigsegv_version & 0xff);
printf("openssl: %s\n", SSLeay_version(SSLEAY_VERSION));
printf("curses: %s\n", curses_version());
2015-10-31 22:10:01 +03:00
printf("libuv: %s\n", uv_version_string());
}
2015-11-27 21:52:24 +03:00
void
_stop_exit(c3_i int_i)
{
fprintf(stderr, "\r\n[received keyboard stop signal, exiting]\r\n");
u3_lo_bail();
}
2013-09-29 00:21:18 +04:00
c3_i
main(c3_i argc,
c3_c** argv)
{
// Parse options.
//
2014-11-05 04:18:47 +03:00
if ( c3n == _main_getopt(argc, argv) ) {
2014-09-11 04:01:32 +04:00
u3_ve_usage(argc, argv);
2013-09-29 00:21:18 +04:00
return 1;
}
if ( c3y == u3_Host.ops_u.rep ) {
report();
return 0;
}
if ( c3y == u3_Host.ops_u.nuu ) {
struct stat s;
if ( !stat(u3_Host.dir_c, &s) ) {
fprintf(stderr, "tried to create, but %s already exists\n", u3_Host.dir_c);
fprintf(stderr, "normal usage: %s %s\n", argv[0], u3_Host.dir_c);
exit(1);
2015-11-17 06:29:27 +03:00
}
} else {
struct stat s;
if ( -1 == stat(u3_Host.dir_c, &s) ) {
fprintf(stderr, "%s: urbit not found\n", u3_Host.dir_c);
u3_ve_usage(argc, argv);
}
2015-10-10 04:31:07 +03:00
}
2015-10-27 00:03:14 +03:00
2015-10-18 06:29:59 +03:00
#if 0
2015-10-10 04:31:07 +03:00
if ( 0 == getuid() ) {
chroot(u3_Host.dir_c);
u3_Host.dir_c = "/";
}
2015-10-18 06:29:59 +03:00
#endif
2014-09-11 04:01:32 +04:00
u3_ve_sysopt();
2013-09-29 00:21:18 +04:00
2015-10-27 00:03:14 +03:00
// Block profiling signal, which should be delievered to exactly one thread.
//
if ( _(u3_Host.ops_u.pro) ) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPROF);
if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) {
perror("pthread_sigmask");
exit(1);
}
}
2015-11-27 21:52:24 +03:00
// Handle SIGTSTP as if it was SIGTERM.
//
signal(SIGTSTP, _stop_exit);
2014-06-10 01:56:56 +04:00
printf("~\n");
2015-06-06 01:07:40 +03:00
// printf("welcome.\n");
2016-10-25 17:53:44 +03:00
printf("urbit %s\n", URBIT_VERSION);
2015-06-06 01:07:40 +03:00
printf("urbit: home is %s\n", u3_Host.dir_c);
// printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c);
2014-11-05 04:18:47 +03:00
if ( c3y == u3_Host.ops_u.dem && c3n == u3_Host.ops_u.bat ) {
2015-06-06 01:07:40 +03:00
printf("urbit: running as daemon\n");
2013-09-29 00:21:18 +04:00
}
2014-09-23 21:11:59 +04:00
// Seed prng. Don't panic -- just for fuzz testing.
2014-03-04 23:17:34 +04:00
//
srand(getpid());
2013-09-29 00:21:18 +04:00
// Instantiate process globals.
{
2014-11-29 05:19:11 +03:00
/* Boot the image and checkpoint. Set flags.
2014-09-11 04:01:32 +04:00
*/
2014-11-29 05:19:11 +03:00
{
/* Set pier directory.
*/
u3C.dir_c = u3_Host.dir_c;
/* Set GC flag.
*/
if ( _(u3_Host.ops_u.gab) ) {
u3C.wag_w |= u3o_debug_ram;
}
/* Set profile flag.
*/
if ( _(u3_Host.ops_u.pro) ) {
u3C.wag_w |= u3o_debug_cpu;
}
/* Set verbose flag.
*/
if ( _(u3_Host.ops_u.veb) ) {
u3C.wag_w |= u3o_verbose;
}
2015-05-20 03:04:08 +03:00
/* Set quiet flag.
*/
if ( _(u3_Host.ops_u.qui) ) {
u3C.wag_w |= u3o_quiet;
}
2014-12-01 03:06:08 +03:00
/* Set dry-run flag.
*/
if ( _(u3_Host.ops_u.dry) ) {
u3C.wag_w |= u3o_dryrun;
}
2014-11-29 05:19:11 +03:00
}
u3m_boot(u3_Host.ops_u.nuu,
u3_Host.ops_u.gab,
u3_Host.dir_c,
u3_Host.ops_u.pil_c);
2013-09-29 00:21:18 +04:00
2014-09-24 11:38:37 +04:00
/* Start Arvo.
2014-09-11 04:01:32 +04:00
*/
2014-10-11 09:32:58 +04:00
#if 1
2013-09-29 00:21:18 +04:00
{
2014-09-11 04:01:32 +04:00
struct timeval tim_tv;
u3_noun now;
2013-09-29 00:21:18 +04:00
2014-09-11 04:01:32 +04:00
gettimeofday(&tim_tv, 0);
now = u3_time_in_tv(&tim_tv);
2013-09-29 00:21:18 +04:00
2014-11-06 03:20:01 +03:00
u3v_start(now);
2014-09-24 11:38:37 +04:00
}
2014-10-10 05:27:02 +04:00
#endif
2014-09-25 01:29:19 +04:00
#if 0
2014-09-24 11:38:37 +04:00
/* Initial checkpoint.
*/
2014-11-05 04:18:47 +03:00
if ( _(u3_Host.ops_u.nuu) ) {
2014-09-24 11:38:37 +04:00
printf("about to save.\r\n");
2014-11-06 03:20:01 +03:00
u3e_save();
2014-09-24 11:38:37 +04:00
printf("saved.\r\n");
2013-09-29 00:21:18 +04:00
}
2014-09-25 01:29:19 +04:00
#endif
2013-09-29 00:21:18 +04:00
}
2014-11-06 03:20:01 +03:00
// u3e_grab("main", u3_none);
2015-05-19 21:38:23 +03:00
//
2014-10-10 05:27:02 +04:00
u3_lo_loop();
2014-10-11 09:32:58 +04:00
2013-09-29 00:21:18 +04:00
return 0;
}