Example #1
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;
}
int
dbpriv_count_properties(Objid oid)
{
    Object *o;
    int nprops = 0;

    for (o = dbpriv_find_object(oid); o; o = dbpriv_find_object(o->parent))
	nprops += o->propdefs.cur_length;

    return nprops;
}
static void
insert_prop(Objid oid, int pos, Pval pval)
{
    Pval *new_propval;
    Object *o;
    int i, nprops;

    nprops = dbpriv_count_properties(oid);
    new_propval = mymalloc(nprops * sizeof(Pval), M_PVAL);

    o = dbpriv_find_object(oid);

    for (i = 0; i < pos; i++)
	new_propval[i] = o->propval[i];

    new_propval[pos] = pval;
    new_propval[pos].var = var_ref(pval.var);
    if (new_propval[pos].perms & PF_CHOWN)
	new_propval[pos].owner = o->owner;

    for (i = pos + 1; i < nprops; i++)
	new_propval[i] = o->propval[i - 1];

    if (o->propval)
	myfree(o->propval, M_PVAL);
    o->propval = new_propval;
}
static void
insert_prop_recursively(Objid root, int root_pos, Pval pv)
{
    Objid c;

    insert_prop(root, root_pos, pv);
    pv.var.type = TYPE_CLEAR;	/* do after initial insert_prop so only
				   children will be TYPE_CLEAR */
    for (c = dbpriv_find_object(root)->child;
	 c != NOTHING;
	 c = dbpriv_find_object(c)->sibling) {
	int new_prop_count = dbpriv_find_object(c)->propdefs.cur_length;

	insert_prop_recursively(c, new_prop_count + root_pos, pv);
    }
}
static int
property_defined_at_or_below(const char *pname, int phash, Objid oid)
{
    /* Return true iff some descendant of OID defines a property named PNAME.
     */
    Objid c;
    Proplist *props = &dbpriv_find_object(oid)->propdefs;
    int length = props->cur_length;
    int i;

    for (i = 0; i < length; i++)
	if (props->l[i].hash == phash
	    && !mystrcasecmp(props->l[i].name, pname))
	    return 1;

    for (c = dbpriv_find_object(oid)->child;
	 c != NOTHING;
	 c = dbpriv_find_object(c)->sibling)
	if (property_defined_at_or_below(pname, phash, c))
	    return 1;

    return 0;
}
Example #6
0
void
db_destroy_object(Objid oid)
{
    Object *o = dbpriv_find_object(oid);
    Verbdef *v, *w;
    int i;

    db_priv_affected_callable_verb_lookup();

    if (!o)
	panic("DB_DESTROY_OBJECT: Invalid object!");

    if (o->location != NOTHING || o->contents != NOTHING
	|| o->parent != NOTHING || o->child != NOTHING)
	panic("DB_DESTROY_OBJECT: Not a barren orphan!");

    if (is_user(oid)) {
	Var t;

	t.type = TYPE_OBJ;
	t.v.obj = oid;
	all_users = setremove(all_users, t);
    }
    free_str(o->name);

    for (i = 0; i < o->propdefs.cur_length; i++) {
	/* As an orphan, the only properties on this object are the ones
	 * defined on it directly, so these two arrays must be the same length.
	 */
	free_str(o->propdefs.l[i].name);
	free_var(o->propval[i].var);
    }
    if (o->propval)
	myfree(o->propval, M_PVAL);
    if (o->propdefs.l)
	myfree(o->propdefs.l, M_PROPDEF);

    for (v = o->verbdefs; v; v = w) {
	if (v->program)
	    free_program(v->program);
	free_str(v->name);
	w = v->next;
	myfree(v, M_VERBDEF);
    }

    myfree(objects[oid], M_OBJECT);
    objects[oid] = 0;
}
Example #7
0
int
dbpriv_count_properties(Objid oid)
{
    Var ancestor, ancestors;
    int i, c, nprops = 0;
    Object *o;

    if (NOTHING == oid)
	return 0;

    ancestors = db_ancestors(oid, true);

    FOR_EACH(ancestor, ancestors, i, c) {
	o = dbpriv_find_object(ancestor.v.obj);
	nprops += o->propdefs.cur_length;
    }
Example #8
0
static void
write_object(Objid oid)
{
    Object *o;
    Verbdef *v;
    int i;
    int nverbdefs, nprops;

    if (!valid(oid)) {
	dbio_printf("#%d recycled\n", oid);
	return;
    }
    o = dbpriv_find_object(oid);

    dbio_printf("#%d\n", oid);
    dbio_write_string(o->name);
    dbio_write_string("");	/* placeholder for old handles string */
    dbio_write_num(o->flags);

    dbio_write_objid(o->owner);

    dbio_write_objid(o->location);
    dbio_write_objid(o->contents);
    dbio_write_objid(o->next);

    dbio_write_objid(o->parent);
    dbio_write_objid(o->child);
    dbio_write_objid(o->sibling);
    

    for (v = o->verbdefs, nverbdefs = 0; v; v = v->next)
	nverbdefs++;

    dbio_write_num(nverbdefs);
    for (v = o->verbdefs; v; v = v->next)
	write_verbdef(v);

    dbio_write_num(o->propdefs.cur_length);
    for (i = 0; i < o->propdefs.cur_length; i++)
	write_propdef(&o->propdefs.l[i]);

    nprops = dbpriv_count_properties(oid);

    dbio_write_num(nprops);
    for (i = 0; i < nprops; i++)
	write_propval(o->propval + i);
}
int
db_add_propdef(Objid oid, const char *pname, Var value, Objid owner,
	       unsigned flags)
{
    Object *o;
    Pval pval;
    int i;
    db_prop_handle h;

    h = db_find_property(oid, pname, 0);

    if (h.ptr || property_defined_at_or_below(pname, str_hash(pname), oid))
	return 0;

    o = dbpriv_find_object(oid);
    if (o->propdefs.cur_length == o->propdefs.max_length) {
	Propdef *old_props = o->propdefs.l;
	int new_size = (o->propdefs.max_length == 0
			? 8 : 2 * o->propdefs.max_length);

	o->propdefs.l = mymalloc(new_size * sizeof(Propdef), M_PROPDEF);
	for (i = 0; i < o->propdefs.max_length; i++)
	    o->propdefs.l[i] = old_props[i];
	o->propdefs.max_length = new_size;

	if (old_props)
	    myfree(old_props, M_PROPDEF);
    }
    o->propdefs.l[o->propdefs.cur_length++] = dbpriv_new_propdef(pname);

    pval.var = value;
    pval.owner = owner;
    pval.perms = flags;

    insert_prop_recursively(oid, o->propdefs.cur_length - 1, pval);

    return 1;
}
    }
    o->propdefs.l[o->propdefs.cur_length++] = dbpriv_new_propdef(pname);

    pval.var = value;
    pval.owner = owner;
    pval.perms = flags;

    insert_prop_recursively(oid, o->propdefs.cur_length - 1, pval);

    return 1;
}

int
db_rename_propdef(Objid oid, const char *old, const char *new)
{
    Proplist *props = &dbpriv_find_object(oid)->propdefs;
    int hash = str_hash(old);
    int count = props->cur_length;
    int i;
    db_prop_handle h;

    for (i = 0; i < count; i++) {
	Propdef p;

	p = props->l[i];
	if (p.hash == hash && !mystrcasecmp(p.name, old)) {
	    if (mystrcasecmp(old, new) != 0) {	/* Not changing just the case */
		h = db_find_property(oid, new, 0);
		if (h.ptr
		|| property_defined_at_or_below(new, str_hash(new), oid))
		    return 0;
Example #11
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;
}
Example #12
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;
}
Example #13
0
int
valid(Objid oid)
{
    return dbpriv_find_object(oid) != 0;
}