DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T u

⟦f2f3212d4⟧ TextFile

    Length: 20746 (0x510a)
    Types: TextFile
    Names: »update.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/quipu/update.c« 

TextFile

/* update.c - write EDB back to disk after modify */

#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/update.c,v 7.1 89/12/19 16:20:54 mrose Exp $";
#endif

/*
 * $Header: /f/osi/quipu/RCS/update.c,v 7.1 89/12/19 16:20:54 mrose Exp $
 *
 *
 * $Log:	update.c,v $
 * Revision 7.1  89/12/19  16:20:54  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:18:18  mrose
 * Release 6.0
 * 
 */

/*
 *                                NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include "quipu/util.h"
#include "quipu/entry.h"
#include "tailor.h"
#include "quipu/read.h"
#include "quipu/dua.h"
#include "quipu/connection.h"

#ifndef NO_STATS
extern LLog * log_stat;
#endif
extern int dn_print ();

extern LLog * log_dsap;
extern char remote_lookup;
extern int local_slave_size;
extern int slave_edbs;
struct oper_act *	oper_alloc();
struct oper_act *	make_get_edb_op();

/* routine name is historic - not significant */

journal (myentry)
Entry myentry;
{
char * filename, *dn2edbfile();
char savefile [LINESIZE], newfile[LINESIZE];
DN dn;
extern char * treedir;
extern char * parse_file;
Entry liststart;
extern int errno;

	if (myentry == NULLENTRY) {
		LLOG (log_dsap,LLOG_FATAL,("update edb problem"));
		return NOTOK;
	}

	if ((myentry->e_parent != NULLENTRY) && (myentry->e_parent->e_leaf)) {
		liststart = myentry;
		dn = get_copy_dn (liststart->e_parent);
		if ((filename = dn2edbfile (dn)) == NULLCP) {
			dn_free (dn);
			return NOTOK;
		}
		myentry->e_parent->e_leaf = FALSE;  /* not a leaf now !! */

		if ( write_edb(liststart,filename) != OK)
			return NOTOK;
	} else {
		if (myentry->e_parent == NULLENTRY) {
			liststart = myentry;
			dn = NULLDN;
		} else {
			liststart = myentry->e_parent->e_child;
	 		dn = get_copy_dn (liststart->e_parent);
		}
		if ((filename = dn2edbfile (dn)) == NULLCP) {
			dn_free (dn);
			return NOTOK;
		}

		(void) strcpy (newfile,filename);
		(void) strcat (newfile,".new");

		if ( write_edb(liststart,newfile) != OK) {
		    (void) unlink (newfile);
		    return NOTOK;
		}

		(void) strcpy (savefile,filename);
		(void) strcat (savefile,".bak");

		(void) unlink (savefile);
		if (link (filename, savefile) == NOTOK)
		    SLOG (log_dsap, LLOG_EXCEPTIONS, savefile,
			  ("unable to link %s to", filename));
		if (rename (newfile, filename) == NOTOK) {
		    SLOG (log_dsap, LLOG_EXCEPTIONS, filename,
			  ("unable to rename %s to", newfile));
		    if (link (savefile, filename) == NOTOK
			    && !fileexists (filename))
			LLOG (log_dsap, LLOG_EXCEPTIONS,
			      ("and couldn't get old file back - PANIC!!!"));
		    return NOTOK;
		}
	}

	return OK;
}

modify_attr (eptr,who)
Entry eptr;
DN who;
{
AttributeType at;
AttributeValue av;
AV_Sequence avs;
Attr_Sequence as, old; 
extern int	  no_last_mod;
extern char *new_version ();

	if (no_last_mod)
		return;

	if ((at = AttrT_new (LAST_MOD_OID)) == NULLAttrT) {
		LLOG (log_dsap, LLOG_EXCEPTIONS, ("last mod oid missing"));
		return;
	}

	av = AttrV_alloc ();
	av->av_syntax = str2syntax ("UTCTime");
	av->av_struct = (caddr_t) new_version();

	avs = avs_comp_new(av);

	if ((old = as_find_type (eptr->e_attributes,at)) == NULLATTR) {
		as = as_comp_new (at,avs,NULLACL_INFO);
		eptr->e_attributes = as_merge (eptr->e_attributes,as);
	} else {
		avs_free (old->attr_value);
		old->attr_value = avs;
		AttrT_free (at);
	}

	if ((at = AttrT_new (MOD_BY_OID)) == NULLAttrT) {
		LLOG (log_dsap, LLOG_EXCEPTIONS, ("last mod by oid missing"));
		return;
	}

	av = AttrV_alloc ();
	av->av_syntax = str2syntax ("DN");
	av->av_struct = (caddr_t) dn_cpy (who);

	avs = avs_comp_new(av);

	if ((old = as_find_type (eptr->e_attributes,at)) == NULLATTR) {
		as = as_comp_new (at,avs,NULLACL_INFO);
		eptr->e_attributes = as_merge (eptr->e_attributes,as);
	} else {
		avs_free (old->attr_value);
		old->attr_value = avs;
		AttrT_free (at);
	}
}

do_get_edb (arg,error,result,binddn)
struct getedb_arg *arg;
struct DSError	  *error;
struct getedb_result *result;
DN binddn;
{
Entry eptr;
extern DN mydsadn;
Entry my_entry;
AV_Sequence avs;
struct edb_info * dsainfo;
char proceed = FALSE;
struct dn_seq	* dnseq;
struct di_block	* di;

	(void) dn_decode (arg->ga_entry);

	DLOG (log_dsap,LLOG_DEBUG,("getedb '%s'",arg->ga_version));

	switch(really_find_entry (arg->ga_entry,FALSE,NULLDNSEQ,FALSE,&(eptr),error,&(di)))
	{
	case DS_OK:
	    /*
	    *  Entry has been found and returned via eptr.
	    *  Go through and process this entry.
	    */
	    break;

	case DS_CONTINUE:
	    /*
	    * Get edb operations should never generate referrals.
	    * Free the di_blocks generated and return an error.
	    */
	    error->dse_type = DSE_SERVICEERROR;
	    error->ERR_SERVICE.DSE_sv_problem = DSE_SV_CHAININGREQUIRED;
	    return (DS_X500_ERROR);

	case DS_X500_ERROR:
	    /* something wrong with the request - error should be filled out */
	    return(DS_X500_ERROR);

	default:
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_get_edb() - really_find_entry() failed"));
	    error->dse_type = DSE_SERVICEERROR;
	    error->ERR_SERVICE.DSE_sv_problem = DSE_SV_DITERROR;
	    return (DS_X500_ERROR);
	}

	if ((my_entry = local_find_entry (mydsadn,TRUE)) == NULLENTRY)
		fatal (84,"my entry has gone - no getedb");

	/* Check we will send to this DSA */
	for (avs = my_entry->e_dsainfo->dsa_attr ; avs != NULLAV; avs=avs->avseq_next) {
		if (avs->avseq_av.av_struct == NULL)
			continue;
		dsainfo = (struct edb_info *) avs->avseq_av.av_struct;
		if (dn_cmp(dsainfo->edb_name,arg->ga_entry) == 0) {
			for (dnseq=dsainfo->edb_allowed; dnseq!=NULLDNSEQ; dnseq=dnseq->dns_next) {
				if (dn_cmp(dnseq->dns_dn,binddn) == 0) {
					proceed = TRUE;
					break;
				}
			}
		}
		if (proceed)
			break;
	}
					
	if (!proceed) {
		error->dse_type = DSE_SECURITYERROR;
		error->ERR_SECURITY.DSE_sc_problem = DSE_SC_ACCESSRIGHTS;
		return (DS_ERROR_REMOTE);
	}

	if ((eptr->e_child == NULLENTRY) 
		|| ((eptr->e_child->e_data != E_DATA_MASTER) 
			&& (eptr->e_child->e_data != E_TYPE_SLAVE))) {
		error->dse_type = DSE_SERVICEERROR;
		error->ERR_SERVICE.DSE_sv_problem = DSE_SV_DITERROR;
		return (DS_X500_ERROR);
	}

	if (eptr->e_edbversion != NULLCP) {
		DLOG(log_dsap, LLOG_DEBUG, ("edb_ver = %s", eptr->e_edbversion));

		if (lexequ (arg->ga_version,eptr->e_edbversion) == 0) {
			result->gr_version = eptr->e_edbversion;
			result->gr_edb = NULLENTRY;
			result->gr_next = NULL_GETRESULT;
			return (DS_OK);
		}
	} else 
		eptr->e_edbversion = new_version();

	result->gr_version = eptr->e_edbversion;
	result->gr_edb = eptr->e_child;
	result->gr_next = NULL_GETRESULT;
	return (DS_OK);
}

slave_update () 
{ 
extern time_t lastedb_update, time();

	(void) update_aux (NULLDN, 0); 
	lastedb_update = time((time_t *)0);
}

update_aux (dn, isroot)
DN	dn;
int	isroot;
{
Entry my_entry, make_path();
Entry find_sibling();
extern DN mydsadn;
struct edb_info * dsainfo;
Entry eptr;
static char *version = NULLCP;
AV_Sequence avs;
AV_Sequence avs_head;
int		  success;

	DLOG (log_dsap,LLOG_TRACE,("slave update"));

	if ((my_entry = local_find_entry (mydsadn,TRUE)) == NULLENTRY)
		fatal (82,"Can't update slaves - my entry has gone");

	avs_head = avs_cpy(my_entry->e_dsainfo->dsa_attr);

#ifdef REMOVE_FOR_6_0
	{
	int loop;

	for (loop=0 ; loop <2 ; loop++) {
#endif
	for (avs = avs_head ; avs != NULLAV; avs=avs->avseq_next)
	{
		if (avs->avseq_av.av_struct == NULL)
			continue;
		dsainfo = (struct edb_info *) avs->avseq_av.av_struct;
		if (dsainfo->edb_getfrom == NULLDN)
			continue;  /* not an EDB to update */
		if ((dn || isroot) && dn_cmp (dn, dsainfo -> edb_name) != OK)
		    continue;	   /* not an EDB this time */

		if ((eptr = local_find_entry (dsainfo->edb_name,FALSE)) == NULLENTRY) {
			version = "0000000000Z";
			eptr = make_path (dsainfo->edb_name);
		} 
		else
		{
			if((version = eptr->e_edbversion) == NULLCP)
			{
			    LLOG(log_dsap, LLOG_EXCEPTIONS, ("update_aux: edbversion was NULLCP"));
			    version = "0000000000Z";
			}
		}

#ifdef REMOVE_FOR_6_0
		success = send_get_edb(version, dsainfo->edb_name, dsainfo->edb_getfrom,loop);
#else
		success = send_get_edb(version, dsainfo->edb_name, dsainfo->edb_getfrom);
#endif

		if(dn || isroot)
		    break;

		dsa_wait (0);	/* accept any results of previous ops */

	}
#ifdef REMOVE_FOR_6_0
	}
	}
#endif
	avs_free (avs_head);

	return((dn || isroot) ? success : OK);
}

#ifdef REMOVE_FOR_6_0
int	 send_get_edb (version,dn,from,loop)
char	* version;
DN dn,from;
int loop;
#else
int	 send_get_edb (version,dn,from)
char	* version;
DN dn,from;
#endif
{
struct di_block		* di;
struct DSError		  error;
struct oper_act		* on;
char    buffer[BUFSIZ];
PS	    ps;

#ifdef REMOVE_FOR_6_0
Entry ptr;
		if ((ptr = local_find_entry (from,FALSE)) != NULLENTRY)
			if (quipu_ctx_supported (ptr) == 1) {
				/* probably 5.0 based - send SYNC DAP call */
				if (loop == 0)
					do_sync_getedb (dn,ptr);
				return OK;
			}
	if (loop == 0)
		return OK;
#endif

	switch(get_dsa_info(from, NULLDNSEQ, &(error), &(di)))
	{
	case DS_OK:
	    /*
	    *  di is a completed dsa info block
	    *  Make a get_edb operation from it, attempt to send the operation
	    *  and link the operation onto the global list of get_edb
	    *  operations.
	    */
	    if (ps = ps_alloc (str_open)) {
		if (str_setup (ps, buffer, sizeof buffer, 1) != NOTOK) {
		    ps_printf (ps, "contact ");
		    dn_print (ps, from, EDBOUT);
		    ps_printf (ps, " for ");
		    if (dn)
			dn_print (ps, dn, EDBOUT);
		    *ps -> ps_ptr = NULL;

		    LLOG (log_dsap, LLOG_NOTICE, ("%s", buffer));
		}

		(void) ps_free (ps);
	    }

#ifdef DEBUG
	    DLOG(log_dsap, LLOG_DEBUG, ("send_get_edb - get_dsa_info OK:"));
	    di_list_log(di);
#endif
	    if((on = make_get_edb_op(dn, version, di)) == NULLOPER)
	    {
		/* Flake out screaming */
		LLOG(log_dsap, LLOG_EXCEPTIONS, ("make_get_edb_op failed for send_get_edb"));
		return(NOTOK);
	    }

	    if(oper_chain(on) != OK)
	    {
		LLOG(log_dsap, LLOG_NOTICE, ("Could not chain a getEDB operation"));
		return(NOTOK);
	    }

	    on->on_next_task = get_edb_ops;
	    get_edb_ops = on;
	    return(OK);

	case DS_CONTINUE:
	    /*
	    *  di is a deferred dsa info block
	    *  make the operation and suspend waiting for the di_block to be 
	    *  woken up.
	    */
#ifdef DEBUG
	    DLOG(log_dsap, LLOG_DEBUG, ("send_get_edb - get_dsa_info CONT:"));
	    di_list_log(di);
#endif
	    if((on = make_get_edb_op(dn, version, di)) == NULLOPER)
	    {
		/* Flake out screaming */
		LLOG(log_dsap, LLOG_EXCEPTIONS, ("make_get_edb_op failed for send_get_edb"));
		return(NOTOK);
	    }

	    on->on_state = ON_DEFERRED;

	    on->on_next_task = get_edb_ops;
	    get_edb_ops = on;

	    if (ps = ps_alloc (str_open)) {
		if (str_setup (ps, buffer, sizeof buffer, 1) != NOTOK) {
		    ps_printf (ps, "contact ");
		    dn_print (ps, from, EDBOUT);
		    ps_printf (ps, " for ");
		    if (dn)
			dn_print (ps, dn, EDBOUT);
		    *ps -> ps_ptr = NULL;

		    LLOG (log_dsap, LLOG_NOTICE, ("%s", buffer));
		}

		(void) ps_free (ps);
	    }

	    return(OK);

	case DS_X500_ERROR:
	    /* Error encountered generating di_block */
	    LLOG(log_dsap, LLOG_NOTICE, ("send_get_edb - get_dsa_info returned X500 ERROR"));
	    log_ds_error (&error);
	    ds_error_free (&error);
	    return(NOTOK);

	default:
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("send_get_edb - get_dsa_info unexpected return"));
	    return(NOTOK);
	}
	/* NOTREACHED */
}

process_edb(on)
struct oper_act	* on;
{
extern DN mydsadn;
Entry make_path(), find_sibling();
Entry new_entry, old_entry, temp, sibl, next;
Entry eptr;
			/* up 'n' down to make sure first child !!! */
struct DSError  error;
struct getedb_result	* result = &(on->on_resp.resp_res.dcr_dsres.res_ge);
int entry_cnt = 0;

	if ((eptr = local_find_entry (on->on_req.dca_dsarg.arg_ge.ga_entry,FALSE)) == NULLENTRY) {
		LLOG (log_dsap, LLOG_EXCEPTIONS, ("Updating something which does not exist !!!"));
		return;
	}

	if ((new_entry = result->gr_edb) == NULLENTRY) {
		DLOG (log_dsap, LLOG_NOTICE,("  EDBs are the same (%d): %s",on->on_id,on->on_getedb_ver));
		return;
	} else {
	        DLOG (log_dsap, LLOG_NOTICE,("  EDB updated from (%d): %s to: %s", on->on_id,on->on_getedb_ver, result->gr_version));
		;
	}

	if (eptr->e_edbversion)
		free (eptr->e_edbversion);

	if (result->gr_version == NULLCP) {
		eptr->e_edbversion = "Unknown";
		LLOG(log_dsap, LLOG_EXCEPTIONS, ("EDBRES: NULL version"));
	} else
		eptr->e_edbversion = strdup (result->gr_version);

	for (temp = new_entry; temp != NULLENTRY; temp=temp->e_sibling) {
		temp->e_parent = eptr;
		if (unravel_attribute (temp,&error,TRUE) != OK) {
			LLOG (log_dsap,LLOG_EXCEPTIONS, ("Error in new EDB - continuing with old"));
			log_ds_error (&error);
			return;
		}
	}

	for (temp = new_entry; temp != NULLENTRY; temp=temp->e_sibling) {
		entry_cnt++;
		if ((old_entry = find_sibling (temp->e_name,eptr->e_child)) != NULLENTRY) {
			temp->e_leaf = FALSE;
			temp->e_allchildrenpresent = old_entry->e_allchildrenpresent;
			temp->e_child = old_entry->e_child;
			for (sibl = temp->e_child; sibl != NULLENTRY; sibl=sibl->e_sibling)
				sibl->e_parent = temp;
			if (old_entry->e_edbversion != NULLCP)
				temp->e_edbversion = strdup (old_entry->e_edbversion);
		}

	}

	if (eptr->e_child == NULLENTRY)
		slave_edbs++;

	for (temp = eptr->e_child; temp != NULLENTRY; temp=next) {
		next = temp->e_sibling;
		local_slave_size--;
		entry_free (temp);
	}

	local_slave_size += entry_cnt;
	eptr->e_child = new_entry;

#ifndef NO_STATS
	{
	DN tmp_dn;
	tmp_dn = get_copy_dn (eptr);
	pslog (log_stat,LLOG_NOTICE,"Slave update",dn_print,(caddr_t)tmp_dn);
	dn_free (tmp_dn);
	}
#endif

	if (journal (new_entry) != OK) 
		fatal (-79,"Lost old EDB, can't write new one !!!");

	if (local_find_entry (mydsadn,TRUE) == NULLENTRY)
		fatal (-80,"My entry has disappeared from the DIT !!!");
}

/*
*  get_edb_fail_wakeup suffices for both fail and error conditions
*  arising on a get edb operation.
*/
get_edb_fail_wakeup(on)
struct oper_act	* on;
{
    struct oper_act	* on_tmp;
    struct oper_act	**on_p;

    DLOG(log_dsap, LLOG_TRACE, ("get_edb_fail_wakeup"));

/* Should do extra logging here */

    on_p = &(get_edb_ops);
    for(on_tmp = get_edb_ops; on_tmp != NULLOPER; on_tmp = on_tmp->on_next_task)
    {
	if(on_tmp == on)
	    break;

	on_p = &(on_tmp->on_next_task);
    }

    if(on_tmp != NULLOPER)
    {
	(*on_p) = on_tmp->on_next_task;
    }
    else
    {
	LLOG(log_dsap, LLOG_EXCEPTIONS, ("get_edb_fail_wakeup - op escaped from get_edb_ops (the global list)"));
    }

    oper_conn_extract(on);
    oper_free(on);
}

struct oper_act	* make_get_edb_op(dn, version, di)
DN		  dn;
char		* version;
struct di_block	* di;
{
struct di_block	* di_tmp;
struct oper_act	* on_tmp;
struct getedb_arg	* arg;

	DLOG(log_dsap, LLOG_TRACE, ("make_get_edb_op"));

	if((on_tmp = oper_alloc()) == NULLOPER)
	{
		LLOG(log_dsap, LLOG_EXCEPTIONS, ("make_get_edb_op - out of memory"));
		return(NULLOPER);
	}

	on_tmp->on_type = ON_TYPE_GET_EDB;
	on_tmp->on_arg = &(on_tmp->on_req);
	on_tmp->on_req.dca_dsarg.arg_type = OP_GETEDB;
	on_tmp->on_getedb_ver = version;

	arg = &(on_tmp->on_req.dca_dsarg.arg_ge);

	arg->ga_entry = dn_cpy(dn);
	arg->ga_version = strdup(version);
	DLOG(log_dsap, LLOG_NOTICE, ("EDBARG: ver = %s", arg->ga_version));

	on_tmp->on_dsas = di;
	for(di_tmp=di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
	{
#ifdef DEBUG
	    DLOG(log_dsap, LLOG_DEBUG, ("Linking a di_block to this op"));
	    di_log(di_tmp);
#endif
	    di_tmp->di_type = DI_OPERATION;
	    di_tmp->di_oper = on_tmp;
	}

	return(on_tmp);
}

get_edb_extract(on)
struct oper_act	* on;
{
    struct oper_act	* on_tmp;
    struct oper_act	**next_on;

    next_on = &(get_edb_ops);
    for(on_tmp=get_edb_ops; on_tmp!=NULLOPER; on_tmp=on_tmp->on_next_task)
    {
	if(on_tmp == on)
	    break;
	next_on = &(on_tmp->on_next_task);
    }
    if(on_tmp != NULLOPER)
    {
	(*next_on) = on_tmp->on_next_task;
    }
    else
    {
	LLOG(log_dsap, LLOG_EXCEPTIONS, ("Not on get_edb list"));
    }
}

#ifdef REMOVE_FOR_6_0
Entry read_edb (version,dn,addr)
char ** version;
DN dn;
struct PSAPaddr * addr;
{
struct DSError error;
static struct ds_bind_arg bindarg;
static struct ds_bind_arg bindresult;
static struct ds_bind_error binderr;
int ad;
struct getedb_arg arg;
struct getedb_result result;
Entry my_entry;
extern DN mydsdn;
char * passwd, *get_entry_passwd();

	/* read from of remote DSA */
	/* Do synchronus read for now */
	/* Async read eventually */

	{
	    char    buffer[BUFSIZ];
	    PS	    ps;

	    if (ps = ps_alloc (str_open)) {
		if (str_setup (ps, buffer, sizeof buffer, 1) != NOTOK) {
		    ps_printf (ps, "SYNC update of @");
		    if (dn)
			dn_print (ps, dn, EDBOUT);
		    *ps -> ps_ptr = NULL;

/* XXX: should be NOTICE, but since we are synchronous... */
		    LLOG (log_dsap, LLOG_EXCEPTIONS, ("%s", buffer));
		}

		(void) ps_free (ps);
	    }
	}

	bindarg.dba_version = DBA_VERSION_V1988;
	bindarg.dba_auth_type = DBA_AUTH_SIMPLE;
	bindarg.dba_time1 = NULLCP;
	bindarg.dba_time2 = NULLCP;

	if ((my_entry = local_find_entry (mydsadn ,TRUE)) == NULLENTRY) {
		bindarg.dba_dn = NULLDN;
		bindarg.dba_auth_type = DBA_AUTH_NONE;
		bindarg.dba_passwd[0] = 0;
		bindarg.dba_passwd_len = 0;
	} else {
		bindarg.dba_dn = dn_cpy(mydsadn);
		if ( (passwd = get_entry_passwd(my_entry->e_attributes)) != NULLCP) {
			(void) strncpy (bindarg.dba_passwd,passwd,DBA_MAX_PASSWD_LEN);
			bindarg.dba_passwd_len = strlen (passwd);
		} else {
			bindarg.dba_auth_type = DBA_AUTH_NONE;
			bindarg.dba_passwd[0] = 0;
			bindarg.dba_passwd_len = 0;
		}
	}

	if (dap_bind (&ad, &bindarg, &binderr, &bindresult,addr) != OK) {
		LLOG (log_dsap,LLOG_EXCEPTIONS,("getedb bind failed"));
		bind_arg_free (&bindarg);
		return (NULLENTRY);
	}

	bind_arg_free (&bindarg);
	bind_arg_free (&bindresult);

	arg.ga_entry = dn;
	arg.ga_version = *version;
	DLOG(log_dsap, LLOG_NOTICE, ("EDBARG: ver = %s", arg.ga_version));

	if (getedb (&arg,&error,&result,ad) != OK) {
		LLOG (log_dsap,LLOG_EXCEPTIONS,("getedb remote operation failed"));
		log_ds_error (&error);
		ds_error_free (&error);
		(void) dap_unbind (ad);
		return (NULLENTRY);
	}

	(void) dap_unbind (ad);

	*version = result.gr_version;
	if (result.gr_version == NULLCP)
		LLOG(log_dsap, LLOG_NOTICE, ("EDBRES: NULL version"));
	else 
		DLOG(log_dsap, LLOG_NOTICE, ("EDBRES: ver = %s", result.gr_version));

/* XXX: should be NOTICE, but since we are synchronous... */
	if (result.gr_edb == NULLENTRY)
		LLOG (log_dsap, LLOG_EXCEPTIONS,
		      ("  EDBs are the same: %s", *version));
	else
	        LLOG (log_dsap, LLOG_EXCEPTIONS,
		      ("  EDB updated: %s", *version));

	return (result.gr_edb);
}

do_sync_getedb (dn, dsa)
DN	dn;
Entry dsa;
{
Entry make_path();
Entry find_sibling();
extern DN mydsadn;
Entry new_entry, eptr, old_entry, temp, sibl, next;
struct DSError  error;
static char *version = NULLCP;
int entry_cnt = 0;

	DLOG (log_dsap,LLOG_TRACE,("slave update"));

		if ((eptr = local_find_entry (dn,FALSE)) == NULLENTRY) {
			version = "0000000000Z";
			eptr = make_path (dn);
		} else
			version = eptr->e_edbversion;

		if ((new_entry = read_edb (&version,dn,dsa->e_dsainfo->dsa_addr)) == NULLENTRY) 
			return;

		if (version == NULLCP)
			eptr->e_edbversion = "Unknown";
		else
			eptr->e_edbversion = strdup (version);

		for (temp = new_entry; temp != NULLENTRY; temp=temp->e_sibling) {
			temp->e_parent = eptr;
			entry_cnt++;
			if (unravel_attribute (temp,&error,TRUE) != OK) {
				LLOG (log_dsap,LLOG_EXCEPTIONS, ("Error in new EDB - continuing with old"));
				log_ds_error (&error);
				return;
			}

			if ((old_entry = find_sibling (temp->e_name,eptr->e_child)) != NULLENTRY) {
				temp->e_leaf = FALSE;
				temp->e_allchildrenpresent = old_entry->e_allchildrenpresent;
				temp->e_child = old_entry->e_child;
				for (sibl = temp->e_child; sibl != NULLENTRY; sibl=sibl->e_sibling)
					sibl->e_parent = temp;
				if (old_entry->e_edbversion != NULLCP)
					temp->e_edbversion = strdup (old_entry->e_edbversion);
			}

		}
		for (temp = eptr->e_child; temp != NULLENTRY; temp=next) {
			next = temp->e_sibling;
			local_slave_size--;
			entry_free (temp);
		}

		local_slave_size += entry_cnt;

		eptr->e_child = new_entry;
		if (journal (new_entry) != OK)
			fatal (-45,"Lost old EDB, can't write new one !!!");
#ifndef NO_STATS
		else 
			pslog (log_stat,LLOG_NOTICE,"slave update",dn_print,(caddr_t)dn);
#endif
		if (local_find_entry (mydsadn,TRUE) == NULLENTRY)
			fatal (-80,"My entry has disappeared form the DIT !!!");
}
#endif