Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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");
		}

	}

}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
static void
my_warning(void *data, const char *msg)
{
    oklog("PARSER: Warning in %s:\n", program_name(data));
    oklog("           %s\n", msg);
}
Пример #11
0
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;
}