int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor attr_flavor)
{
	int rc = SEPOL_ERR;
	struct cil_bounds *bounds = current->data;
	enum cil_sym_index index;
	struct cil_symtab_datum *parent_datum = NULL;
	struct cil_symtab_datum *child_datum = NULL;

	rc = cil_flavor_to_symtab_index(flavor, &index);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = cil_resolve_name(current, bounds->parent_str, index, extra_args, &parent_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	if (FLAVOR(parent_datum) == attr_flavor) {
		cil_log(CIL_ERR, "Bounds parent %s is an attribute\n", bounds->parent_str);
		rc = SEPOL_ERR;
		goto exit;
	}


	rc = cil_resolve_name(current, bounds->child_str, index, extra_args, &child_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	if (FLAVOR(child_datum) == attr_flavor) {
		cil_log(CIL_ERR, "Bounds child %s is an attribute\n", bounds->child_str);
		rc = SEPOL_ERR;
		goto exit;
	}

	switch (flavor) {
	case CIL_USER: {
		struct cil_user *user = (struct cil_user *)child_datum;

		if (user->bounds != NULL) {
			cil_tree_log(NODE(user->bounds), CIL_ERR, "User %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		user->bounds = (struct cil_user *)parent_datum;
		break;
	}
	case CIL_ROLE: {
		struct cil_role *role = (struct cil_role *)child_datum;

		if (role->bounds != NULL) {
			cil_tree_log(NODE(role->bounds), CIL_ERR, "Role %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		role->bounds = (struct cil_role *)parent_datum;
		break;
	}
	case CIL_TYPE: {
		struct cil_type *type = (struct cil_type *)child_datum;

		if (type->bounds != NULL) {
			cil_tree_log(NODE(type->bounds), CIL_ERR, "Type %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		type->bounds = (struct cil_type *)parent_datum;
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(current, CIL_ERR, "Bad bounds statement");
	return rc;
}
int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor attr_flavor)
{
	int rc = SEPOL_ERR;
	struct cil_bounds *bounds = current->data;
	enum cil_sym_index index;
	struct cil_symtab_datum *parent_datum = NULL;
	struct cil_symtab_datum *child_datum = NULL;

	rc = cil_flavor_to_symtab_index(flavor, &index);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = cil_resolve_name(current, bounds->parent_str, index, extra_args, &parent_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	if (FLAVOR(parent_datum) == attr_flavor) {
		cil_log(CIL_ERR, "Bounds parent %s is an attribute\n", bounds->parent_str);
		rc = SEPOL_ERR;
		goto exit;
	}


	rc = cil_resolve_name(current, bounds->child_str, index, extra_args, &child_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}
	if (FLAVOR(child_datum) == attr_flavor) {
		cil_log(CIL_ERR, "Bounds child %s is an attribute\n", bounds->child_str);
		rc = SEPOL_ERR;
		goto exit;
	}

	switch (flavor) {
	case CIL_USER: {
		struct cil_user *user = (struct cil_user *)child_datum;

		if (user->bounds != NULL) {
			cil_tree_log(NODE(user->bounds), CIL_ERR, "User %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		user->bounds = (struct cil_user *)parent_datum;
		break;
	}
	case CIL_ROLE: {
		struct cil_role *role = (struct cil_role *)child_datum;

		if (role->bounds != NULL) {
			cil_tree_log(NODE(role->bounds), CIL_ERR, "Role %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		role->bounds = (struct cil_role *)parent_datum;
		break;
	}
	case CIL_TYPE: {
		struct cil_type *type = (struct cil_type *)child_datum;

		if (type->bounds != NULL) {
			cil_tree_log(NODE(type->bounds), CIL_ERR, "Type %s already bound by parent", bounds->child_str);
			rc = SEPOL_ERR;
			goto exit;
		}

		type->bounds = (struct cil_type *)parent_datum;
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(current, CIL_ERR, "Bad bounds statement");
	return rc;
}