static int tcp_arguments(int argc, char **argv, int *pport) { char *p = 0; for ( ; argc > 0; argc--, argv++) { if (argc > 0 && (argv[0][0] == '-' || argv[0][0] == '+') && argv[0][1] == 'O' && argv[0][2] == 0 ) { #ifdef OUTBOUND_NETWORK outbound_network_enabled = (argv[0][0] == '+'); #else if (argv[0][0] == '+') { fprintf(stderr, "Outbound network not supported.\n"); oklog("CMDLINE: *** Ignoring %s (outbound network not supported)\n", argv[0]); } #endif } else if (0 == strcmp(argv[0],"-a")) { if (argc <= 1) return 0; argc--; argv++; bind_local_ip = inet_addr(argv[0]); if (bind_local_ip == INADDR_NONE) return 0; oklog("CMDLINE: Source address restricted to %s\n", argv[0]); } else { if (p != 0) /* strtoul always sets p */ return 0; if (0 == strcmp(argv[0],"-p")) { if (argc <= 1) return 0; argc--; argv++; } *pport = strtoul(argv[0], &p, 10); if (*p != '\0') return 0; oklog("CMDLINE: Initial port = %d\n", *pport); } } #ifdef OUTBOUND_NETWORK oklog("CMDLINE: Outbound network connections %s.\n", outbound_network_enabled ? "enabled" : "disabled"); #endif return 1; }
int db_load(void) { dbpriv_set_dbio_input(input_db); str_intern_open(0); oklog("LOADING: %s\n", input_db_name); if (!read_db_file()) { errlog("DB_LOAD: Cannot load database!\n"); return 0; } oklog("LOADING: %s done, will dump new database on %s\n", input_db_name, dump_db_name); str_intern_close(); fclose(input_db); return 1; }
void register_listutils() { oklog("Installing List Utils Extensions v%s\n", lists_version); register_function("iassoc", 2, 3, bf_iassoc, TYPE_ANY, TYPE_LIST, TYPE_INT); register_function("assoc", 2, 3, bf_assoc, TYPE_ANY, TYPE_LIST, TYPE_INT); register_function("sort", 1, 1, bf_sort, TYPE_LIST); register_function("make", 1, 2, bf_make, TYPE_INT, TYPE_ANY); register_function("slice", 1, 2, bf_slice, TYPE_LIST, TYPE_INT); register_function("remove_duplicates", 1, 1, bf_remove_duplicates, TYPE_LIST); }
static int write_db_file(const char *reason) { Objid oid; Objid max_oid = db_last_used_objid(); Verbdef *v; Var user_list; int i; volatile int nprogs = 0; volatile int success = 1; for (oid = 0; oid <= max_oid; oid++) { if (valid(oid)) for (v = dbpriv_find_object(oid)->verbdefs; v; v = v->next) if (v->program) nprogs++; } user_list = db_all_users(); TRY { dbio_printf(header_format_string, current_db_version); dbio_printf("%d\n%d\n%d\n%d\n", max_oid + 1, nprogs, 0, user_list.v.list[0].v.num); for (i = 1; i <= user_list.v.list[0].v.num; i++) dbio_write_objid(user_list.v.list[i].v.obj); oklog("%s: Writing %d objects...\n", reason, max_oid + 1); for (oid = 0; oid <= max_oid; oid++) { write_object(oid); if (oid == max_oid || log_report_progress()) oklog("%s: Done writing %d objects...\n", reason, oid + 1); } oklog("%s: Writing %d MOO verb programs...\n", reason, nprogs); for (i = 0, oid = 0; oid <= max_oid; oid++) if (valid(oid)) { int vcount = 0; for (v = dbpriv_find_object(oid)->verbdefs; v; v = v->next) { if (v->program) { dbio_printf("#%d:%d\n", oid, vcount); dbio_write_program(v->program); if (++i == nprogs || log_report_progress()) oklog("%s: Done writing %d verb programs...\n", reason, i); } vcount++; } } oklog("%s: Writing forked and suspended tasks...\n", reason); write_task_queue(); oklog("%s: Writing list of formerly active connections...\n", reason); write_active_connections(); } EXCEPT(dbpriv_dbio_failed) success = 0; ENDTRY; return success; }
void str_intern_close(void) { int i; struct intern_entry *e, *next; for (i = 0; i < intern_table_size; i++) { for (e = intern_table[i]; e; e = next) { next = e->next; free_str(e->s); /* myfree(e, M_INTERN_ENTRY); */ } } myfree(intern_table, M_INTERN_POINTER); intern_table = NULL; free_intern_entry_hunks(); oklog("INTERN: %d allocations saved, %d bytes\n", intern_allocations_saved, intern_bytes_saved); oklog("INTERN: at end, %d entries in a %d bucket hash table.\n", intern_table_count, intern_table_size); }
static void do_mysql_comms(int to_server, int from_server) { struct sql_request req; static char *buffer = 0; static int buflen = 0; static char *serial; Timer_ID id; Var args; Var result; set_server_cmdline("(MOO mysql-client slave)"); my_handle = moomysql_open_connection(SQLHOST, SQLUSER, SQLPASS, SQLDB, SQLPORT, 0); for (;;) { oklog("MYSQL CHILD: ready to read!\n"); if (robust_read(from_server, &req, sizeof(req)) != sizeof(req)) end_sql(); oklog("MYSQL CHILD read!\n"); if (req.length) { ensure_buffer(&buffer, &buflen, req.length + 1); if (robust_read(from_server, buffer, req.length) != req.length) end_sql(); buffer[req.length] = '\0'; oklog("MYSQL CHILD got stuff!\n"); args = deserialize(buffer); } id = set_timer(req.timeout, timeout_proc, 0); if (req.kind == SQLREQ_DO_QUERY) { oklog("MYSQL CHILD: doing query '%s'\n", args.v.list[1].v.str); result = moomysql_send_query(my_handle, args.v.list[1].v.str); oklog("got result: %s\n", value2str(result)); serial = serialize(result); oklog("MYSQL CHILD: serialized!\n"); req.length = strlen(serial); oklog("MYSQL CHILD: strlenned!\n"); } else if (req.kind == SQLREQ_GET_ROW) { result = moomysql_next_row(my_handle); serial = serialize(result); req.length = strlen(serial); } else { req.kind = SQLREQ_ERROR; req.length = 0; } oklog("MYSQL CHILD: writing..\n"); write(to_server, &req, sizeof(req)); oklog("MYSQL CHILD: wrote req..\n"); if (req.length) { write(to_server, serial, req.length); oklog("MYSQL CHILD: wrote serial..\n"); free(serial); oklog("MYSQL CHILD: freed serial!\n"); } } }
static int dump_database(Dump_Reason reason) { Stream *s = new_stream(100); char *temp_name; FILE *f; int success; retryDumping: stream_printf(s, "%s.#%d#", dump_db_name, dump_generation); remove(reset_stream(s)); /* Remove previous checkpoint */ if (reason == DUMP_PANIC) stream_printf(s, "%s.PANIC", dump_db_name); else { dump_generation++; stream_printf(s, "%s.#%d#", dump_db_name, dump_generation); } temp_name = reset_stream(s); oklog("%s on %s ...\n", reason_names[reason], temp_name); #ifdef UNFORKED_CHECKPOINTS reset_command_history(); #else if (reason == DUMP_CHECKPOINT) { switch (fork_server("checkpointer")) { case FORK_PARENT: reset_command_history(); free_stream(s); return 1; case FORK_ERROR: free_stream(s); return 0; case FORK_CHILD: set_server_cmdline("(MOO checkpointer)"); break; } } #endif success = 1; if ((f = fopen(temp_name, "w")) != 0) { dbpriv_set_dbio_output(f); if (!write_db_file(reason_names[reason])) { log_perror("Trying to dump database"); fclose(f); remove(temp_name); if (reason == DUMP_CHECKPOINT) { errlog("Abandoning checkpoint attempt...\n"); success = 0; } else { int retry_interval = 60; errlog("Waiting %d seconds and retrying dump...\n", retry_interval); timer_sleep(retry_interval); goto retryDumping; } } else { fclose(f); oklog("%s on %s finished\n", reason_names[reason], temp_name); if (reason != DUMP_PANIC) { remove(dump_db_name); if (rename(temp_name, dump_db_name) != 0) { log_perror("Renaming temporary dump file"); success = 0; } } } } else { log_perror("Opening temporary dump file"); success = 0; } free_stream(s); #ifndef UNFORKED_CHECKPOINTS if (reason == DUMP_CHECKPOINT) /* We're a child, so we'd better go away. */ exit(!success); #endif return success; }
static int read_db_file(void) { Objid oid; int nobjs, nprogs, nusers; Var user_list; int i, vnum, dummy; db_verb_handle h; Program *program; waif_before_loading(); if (dbio_scanf(header_format_string, &dbio_input_version) != 1) dbio_input_version = DBV_Prehistory; if (!check_version(dbio_input_version)) { errlog("READ_DB_FILE: Unknown DB version number: %d\n", dbio_input_version); return 0; } /* I use a `dummy' variable here and elsewhere instead of the `*' * assignment-suppression syntax of `scanf' because it allows more * straightforward error checking; unfortunately, the standard says that * suppressed assignments are not counted in determining the returned value * of `scanf'... */ if (dbio_scanf("%d\n%d\n%d\n%d\n", &nobjs, &nprogs, &dummy, &nusers) != 4) { errlog("READ_DB_FILE: Bad header\n"); return 0; } user_list = new_list(nusers); for (i = 1; i <= nusers; i++) { user_list.v.list[i].type = TYPE_OBJ; user_list.v.list[i].v.obj = dbio_read_objid(); } dbpriv_set_all_users(user_list); oklog("LOADING: Reading %d objects...\n", nobjs); for (i = 1; i <= nobjs; i++) { if (!read_object()) { errlog("READ_DB_FILE: Bad object #%d.\n", i - 1); return 0; } if (i % 10000 == 0 || i == nobjs) oklog("LOADING: Done reading %d objects ...\n", i); } if (!validate_hierarchies()) { errlog("READ_DB_FILE: Errors in object hierarchies.\n"); return 0; } oklog("LOADING: Reading %d MOO verb programs...\n", nprogs); for (i = 1; i <= nprogs; i++) { if (dbio_scanf("#%d:%d\n", &oid, &vnum) != 2) { errlog("READ_DB_FILE: Bad program header, i = %d.\n", i); return 0; } if (!valid(oid)) { errlog("READ_DB_FILE: Verb for non-existant object: #%d:%d.\n", oid, vnum); return 0; } h = db_find_indexed_verb(oid, vnum + 1); /* DB file is 0-based. */ if (!h.ptr) { errlog("READ_DB_FILE: Unknown verb index: #%d:%d.\n", oid, vnum); return 0; } program = dbio_read_program(dbio_input_version, fmt_verb_name, &h); if (!program) { errlog("READ_DB_FILE: Unparsable program #%d:%d.\n", oid, vnum); return 0; } db_set_verb_program(h, program); if (i % 5000 == 0 || i == nprogs) oklog("LOADING: Done reading %d verb programs...\n", i); } oklog("LOADING: Reading forked and suspended tasks...\n"); if (!read_task_queue()) { errlog("READ_DB_FILE: Can't read task queue.\n"); return 0; } oklog("LOADING: Reading list of formerly active connections...\n"); if (!read_active_connections()) { errlog("DB_READ: Can't read active connections.\n"); return 0; } waif_after_loading(); return 1; }
static int validate_hierarchies() { Objid oid, log_oid; Objid size = db_last_used_objid() + 1; int broken = 0; int fixed_nexts = 0; oklog("VALIDATING the object hierarchies ...\n"); # define PROGRESS_INTERVAL 10000 # define MAYBE_LOG_PROGRESS \ { \ if (oid == log_oid) { \ log_oid += PROGRESS_INTERVAL; \ oklog("VALIDATE: Done through #%d ...\n", oid); \ } \ } oklog("VALIDATE: Phase 1: Check for invalid objects ...\n"); for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { if (o->location == NOTHING && o->next != NOTHING) { o->next = NOTHING; fixed_nexts++; } # define CHECK(field, name) \ { \ if (o->field != NOTHING \ && !dbpriv_find_object(o->field)) { \ errlog("VALIDATE: #%d.%s = #%d <invalid> ... fixed.\n", \ oid, name, o->field); \ o->field = NOTHING; \ } \ } CHECK(parent, "parent"); CHECK(child, "child"); CHECK(sibling, "sibling"); CHECK(location, "location"); CHECK(contents, "contents"); CHECK(next, "next"); # undef CHECK } } if (fixed_nexts != 0) errlog("VALIDATE: Fixed %d should-be-null next pointer(s) ...\n", fixed_nexts); /* * The next two phases are only done if the moo is launched with -r * and can be used with DBs that have broken hierarchies. */ if (recovery_mode) { oklog("EMERGENCY REBUILD PHASE 1: Removing old contents and child lists ...\n"); for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { o->contents = NOTHING; o->next = NOTHING; o->child = NOTHING; o->sibling = NOTHING; } } oklog("EMERGENCY REBUILD PHASE 2: Rebuilding contents and child lists ...\n"); for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { /* find this obj's parent & loc */ Objid parent = o->parent; Objid location = o->location; if (parent != NOTHING) { Object *po = dbpriv_find_object(parent); Objid lastchild = po->lastchild; if (lastchild != NOTHING) { Object *co = dbpriv_find_object(lastchild); co->sibling = oid; po->lastchild = oid; } else { po->child = oid; po->lastchild = oid; } } if (location != NOTHING) { Object *lo = dbpriv_find_object(location); Objid lastcontents = lo->lastcontents; if (lastcontents != NOTHING) { Object *co = dbpriv_find_object(lastcontents); co->next = oid; lo->lastcontents = oid; } else { lo->contents = oid; lo->lastcontents = oid; } } } /* endif o */ } /* for oid */ } /* recovery_mode */ oklog("VALIDATE: Phase 2: Check for cycles ...\n"); for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) { Object *o = dbpriv_find_object(oid); Objid list_end; MAYBE_LOG_PROGRESS; if (o) { # define CHECK(start, field, name) \ { \ Objid oid2 = start; \ int count = 0; \ for (; oid2 != NOTHING \ ; oid2 = dbpriv_find_object(oid2)->field) { \ if (++count > size) { \ errlog("VALIDATE: Cycle in `%s' chain of #%d\n",\ name, oid); \ broken = 1; \ break; \ } \ list_end = oid2; \ } \ } CHECK(o->parent, parent, "parent"); list_end = NOTHING; CHECK(o->child, sibling, "child"); o->lastchild = list_end; CHECK(o->location, location, "location"); list_end = NOTHING; CHECK(o->contents, next, "contents"); o->lastcontents = list_end; # undef CHECK } } if (broken) /* Can't continue if cycles found */ return 0; oklog("VALIDATING the object hierarchies ... finished.\n"); return !broken; }
static void my_warning(void *data, const char *msg) { oklog("PARSER: Warning in %s:\n", program_name(data)); oklog(" %s\n", msg); }
static int validate_hierarchies() { Objid oid; Objid size = db_last_used_objid() + 1; int broken = 0; int fixed_nexts = 0; oklog("VALIDATING the object hierarchies ...\n"); # define MAYBE_LOG_PROGRESS \ { \ if (log_report_progress()) { \ oklog("VALIDATE: Done through #%d ...\n", oid); \ } \ } oklog("VALIDATE: Phase 1: Check for invalid objects ...\n"); for (oid = 0; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { if (o->location == NOTHING && o->next != NOTHING) { o->next = NOTHING; fixed_nexts++; } # define CHECK(field, name) \ { \ if (o->field != NOTHING \ && !dbpriv_find_object(o->field)) { \ errlog("VALIDATE: #%d.%s = #%d <invalid> ... fixed.\n", \ oid, name, o->field); \ o->field = NOTHING; \ } \ } CHECK(parent, "parent"); CHECK(child, "child"); CHECK(sibling, "sibling"); CHECK(location, "location"); CHECK(contents, "contents"); CHECK(next, "next"); # undef CHECK } } if (fixed_nexts != 0) errlog("VALIDATE: Fixed %d should-be-null next pointer(s) ...\n", fixed_nexts); oklog("VALIDATE: Phase 2: Check for cycles ...\n"); for (oid = 0; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { # define CHECK(start, field, name) \ { \ Objid slower = start; \ Objid faster = slower; \ while (faster != NOTHING) { \ faster = dbpriv_find_object(faster)->field; \ if (faster == NOTHING) \ break; \ faster = dbpriv_find_object(faster)->field; \ slower = dbpriv_find_object(slower)->field; \ if (faster == slower) { \ errlog("VALIDATE: Cycle in `%s' chain of #%d\n", \ name, oid); \ broken = 1; \ break; \ } \ } \ } CHECK(o->parent, parent, "parent"); CHECK(o->child, sibling, "child"); CHECK(o->location, location, "location"); CHECK(o->contents, next, "contents"); # undef CHECK /* setup for phase 3: set two temp flags on every object */ o->flags |= (3<<FLAG_FIRST_TEMP); } } if (broken) /* Can't continue if cycles found */ return 0; oklog("VALIDATE: Phase 3a: Finding delusional parents ...\n"); for (oid = 0; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { # define CHECK(up, down, down_name, across, FLAG) \ { \ Objid oidkid; \ Object *okid; \ \ for (oidkid = o->down; \ oidkid != NOTHING; \ oidkid = okid->across) { \ \ okid = dbpriv_find_object(oidkid); \ if (okid->up != oid) { \ errlog( \ "VALIDATE: #%d erroneously on #%d's %s list.\n", \ oidkid, oid, down_name); \ broken = 1; \ } \ else { \ /* mark okid as properly claimed */ \ okid->flags &= ~(1<<(FLAG)); \ } \ } \ } CHECK(parent, child, "child", sibling, FLAG_FIRST_TEMP); CHECK(location, contents, "contents", next, FLAG_FIRST_TEMP+1); # undef CHECK } } oklog("VALIDATE: Phase 3b: Finding delusional children ...\n"); for (oid = 0; oid < size; oid++) { Object *o = dbpriv_find_object(oid); MAYBE_LOG_PROGRESS; if (o) { # define CHECK(up, up_name, down_name, FLAG) \ { \ /* If oid is unclaimed, up must be NOTHING */ \ if ((o->flags & (1<<(FLAG))) && o->up != NOTHING) { \ errlog("VALIDATE: #%d not in %s (#%d)'s %s list.\n", \ oid, up_name, o->up, down_name); \ broken = 1; \ } \ } CHECK(parent, "parent", "child", FLAG_FIRST_TEMP); CHECK(location, "location", "contents", FLAG_FIRST_TEMP+1); /* clear temp flags */ o->flags &= ~(3<<FLAG_FIRST_TEMP); # undef CHECK } } oklog("VALIDATING the object hierarchies ... finished.\n"); return !broken; }