int bsi_flags;
#define BSQL_SF_ALL_OPER 0x0001
#define BSQL_SF_FILTER_HASSUBORDINATE 0x0002
+#define BSQL_SF_FILTER_ENTRYUUID 0x0004
struct berval *bsi_base_ndn;
backsql_entryID bsi_base_id;
* method = LDAP_AUTH_SIMPLE
*/
rs->sr_err = backsql_get_db_conn( op, &dbh );
- if (!dbh) {
+ if ( !dbh ) {
Debug( LDAP_DEBUG_TRACE, "backsql_bind(): "
"could not get connection handle - exiting\n",
0, 0, 0 );
#include "slap.h"
#include "proto-sql.h"
+#include "lutil.h"
/*
* sets the supported operational attributes (if required)
*/
+Attribute *
+backsql_operational_entryUUID( backsql_info *bi, backsql_entryID *id )
+{
+ int rc;
+ struct berval val, nval;
+ AttributeDescription *desc = slap_schema.si_ad_entryUUID;
+ Attribute *a;
+
+ backsql_entryUUID( bi, id, &val, NULL );
+
+ rc = (*desc->ad_type->sat_equality->smr_normalize)(
+ SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+ desc->ad_type->sat_syntax,
+ desc->ad_type->sat_equality,
+ &val, &nval, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ ber_memfree( val.bv_val );
+ return NULL;
+ }
+
+ a = ch_malloc( sizeof( Attribute ) );
+ a->a_desc = desc;
+
+ a->a_vals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ a->a_vals[ 0 ] = val;
+ BER_BVZERO( &a->a_vals[ 1 ] );
+
+ a->a_nvals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+ a->a_nvals[ 0 ] = nval;
+ BER_BVZERO( &a->a_nvals[ 1 ] );
+
+ a->a_next = NULL;
+ a->a_flags = 0;
+
+ return a;
+}
+
+Attribute *
+backsql_operational_entryCSN( Operation *op )
+{
+ char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
+ struct berval entryCSN;
+ Attribute *a;
+
+ a = ch_malloc( sizeof( Attribute ) );
+ a->a_desc = slap_schema.si_ad_entryCSN;
+ a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );
+ BER_BVZERO( &a->a_vals[ 1 ] );
+
+ slap_get_csn( op, csnbuf, sizeof(csnbuf), &entryCSN, 0 );
+ ber_dupbv( &a->a_vals[ 0 ], &entryCSN );
+
+ a->a_nvals = a->a_vals;
+
+ a->a_next = NULL;
+ a->a_flags = 0;
+
+ return a;
+}
+
int
backsql_operational(
Operation *op,
SQLHDBC dbh = SQL_NULL_HDBC;
int rc = 0;
Attribute **ap;
+ enum {
+ BACKSQL_OP_HASSUBORDINATES = 0,
+ BACKSQL_OP_ENTRYUUID,
+ BACKSQL_OP_ENTRYCSN,
+
+ BACKSQL_OP_LAST
+ };
+ int get_conn = BACKSQL_OP_LAST,
+ got[ BACKSQL_OP_LAST ] = { 0 };
Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry \"%s\"\n",
rs->sr_entry->e_nname.bv_val, 0, 0 );
- for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next )
- /* just count */ ;
+ for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
+ if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
+ get_conn--;
+ got[ BACKSQL_OP_HASSUBORDINATES ] = 1;
- if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) )
- && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL ) {
-
- rc = backsql_get_db_conn( op, &dbh );
- if ( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
- "could not get connection handle - exiting\n",
- 0, 0, 0 );
- return 1;
+ } else if ( (*ap)->a_desc == slap_schema.si_ad_entryUUID ) {
+ get_conn--;
+ got[ BACKSQL_OP_ENTRYUUID ] = 1;
+
+ } else if ( (*ap)->a_desc == slap_schema.si_ad_entryCSN ) {
+ get_conn--;
+ got[ BACKSQL_OP_ENTRYCSN ] = 1;
}
-
+ }
+
+ if ( !get_conn ) {
+ return 0;
+ }
+
+ rc = backsql_get_db_conn( op, &dbh );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+ "could not get connection handle - exiting\n",
+ 0, 0, 0 );
+ return 1;
+ }
+
+ if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) )
+ && !got[ BACKSQL_OP_HASSUBORDINATES ]
+ && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL )
+ {
rc = backsql_has_children( bi, dbh, &rs->sr_entry->e_nname );
switch( rc ) {
default:
Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
"has_children failed( %d)\n", rc, 0, 0 );
- rc = 1;
- break;
+ return 1;
+ }
+ }
+
+ if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_entryUUID, rs->sr_attrs ) )
+ && !got[ BACKSQL_OP_ENTRYUUID ]
+ && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID ) == NULL )
+ {
+ struct berval ndn;
+ backsql_srch_info bsi;
+
+ ndn = rs->sr_entry->e_nname;
+ if ( backsql_api_dn2odbc( op, rs, &ndn ) ) {
+ Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+ "backsql_api_dn2odbc failed\n",
+ 0, 0, 0 );
+ return 1;
}
+
+ rc = backsql_init_search( &bsi, &ndn, LDAP_SCOPE_BASE,
+ -1, -1, -1, NULL, dbh, op, rs, NULL, 1 );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+ "could not retrieve entry ID - no such entry\n",
+ 0, 0, 0 );
+ return 1;
+ }
+
+ *ap = backsql_operational_entryUUID( bi, &bsi.bsi_base_id );
+
+ (void)backsql_free_entryID( &bsi.bsi_base_id, 0 );
+
+ if ( ndn.bv_val != rs->sr_entry->e_nname.bv_val ) {
+ free( ndn.bv_val );
+ }
+
+ if ( *ap == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+ "could not retrieve entryUUID\n",
+ 0, 0, 0 );
+ return 1;
+ }
+
+ ap = &(*ap)->a_next;
+ }
+
+ if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_entryCSN, rs->sr_attrs ) )
+ && !got[ BACKSQL_OP_ENTRYCSN ]
+ && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ) == NULL )
+ {
+ *ap = backsql_operational_entryCSN( op );
+ if ( *ap == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+ "could not retrieve entryCSN\n",
+ 0, 0, 0 );
+ return 1;
+ }
+
+ ap = &(*ap)->a_next;
}
- Debug( LDAP_DEBUG_TRACE, "<==backsql_operational()\n", 0, 0, 0);
+ Debug( LDAP_DEBUG_TRACE, "<==backsql_operational(%d)\n", rc, 0, 0);
return rc;
}
/* turns an ID into an entry */
int backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *id );
+/*
+ * operational.c
+ */
+
+Attribute *backsql_operational_entryUUID( backsql_info *bi, backsql_entryID *id );
+
+Attribute *backsql_operational_entryCSN( Operation *op );
+
/*
* schema-map.c
*/
int backsql_prepare_pattern( BerVarray split_pattern, BerVarray values,
struct berval *res );
+int backsql_entryUUID( backsql_info *bi, backsql_entryID *id,
+ struct berval *entryUUID, void *memctx );
+int backsql_entryUUID_decode( struct berval *entryUUID, unsigned long *oc_id,
+#ifdef BACKSQL_ARBITRARY_KEY
+ struct berval *keyval
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ unsigned long *keyval
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+ );
+
#endif /* PROTO_SQL_H */
* Turn structuralObjectClass into objectClass
*/
if ( ad == slap_schema.si_ad_objectClass
- || ad == slap_schema.si_ad_structuralObjectClass ) {
+ || ad == slap_schema.si_ad_structuralObjectClass )
+ {
/*
* If the filter is LDAP_FILTER_PRESENT, then it's done;
* otherwise, let's see if we are lucky: filtering
goto done;
}
+ } else if ( ad == slap_schema.si_ad_entryUUID ) {
+ unsigned long oc_id;
+#ifdef BACKSQL_ARBITRARY_KEY
+ struct berval keyval;
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ unsigned long keyval;
+ char keyvalbuf[] = "18446744073709551615";
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
+
+ if ( oc_id != bsi->bsi_oc->bom_id ) {
+ bsi->bsi_status = LDAP_SUCCESS;
+ rc = -1;
+ goto done;
+ }
+
+#ifdef BACKSQL_ARBITRARY_KEY
+ backsql_strfcat( &bsi->bsi_flt_where, "bcblbc",
+ &bsi->bsi_oc->bom_keytbl, '.',
+ &bsi->bsi_oc->bom_keycol,
+ STRLENOF( " LIKE '" ), " LIKE '",
+ &keyval, '\'' );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
+ backsql_strfcat( &bsi->bsi_flt_where, "bcbcs",
+ &bsi->bsi_oc->bom_keytbl, '.',
+ &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ backsql_strfcat( &bsi->bsi_flt_where, "l",
+ (ber_len_t)STRLENOF( "1=1" ), "1=1" );
+ break;
+
+ default:
+ rc = -1;
+ goto done;
+ }
+
+ bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
+ rc = 1;
+ goto done;
+
} else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
/*
* FIXME: this is not robust; e.g. a filter
eid = backsql_free_entryID( eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
{
int rc;
- Attribute *hasSubordinate = NULL,
+ Attribute *a_hasSubordinate = NULL,
+ *a_entryUUID = NULL,
*a = NULL;
Entry *e = NULL;
switch ( rc ) {
case LDAP_COMPARE_TRUE:
case LDAP_COMPARE_FALSE:
- hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
- if ( hasSubordinate != NULL ) {
+ a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
+ if ( a_hasSubordinate != NULL ) {
for ( a = user_entry.e_attrs;
a && a->a_next;
a = a->a_next );
- a->a_next = hasSubordinate;
+ a->a_next = a_hasSubordinate;
}
rc = 0;
break;
}
}
- if ( test_filter( op, e, op->ors_filter )
- == LDAP_COMPARE_TRUE ) {
- if ( hasSubordinate && !( bsi.bsi_flags & BSQL_SF_ALL_OPER )
- && !ad_inlist( slap_schema.si_ad_hasSubordinates, op->ors_attrs ) ) {
+ if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
+ a_entryUUID = backsql_operational_entryUUID( bi, eid );
+ if ( a_entryUUID != NULL ) {
+ for ( a = user_entry.e_attrs;
+ a && a->a_next;
+ a = a->a_next );
+
+ a->a_next = a_entryUUID;
+ }
+ }
+
+ if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
+ {
+#if 0
+ if ( a_hasSubordinate && !( bsi.bsi_flags & BSQL_SF_ALL_OPER )
+ && !ad_inlist( slap_schema.si_ad_hasSubordinates, op->ors_attrs ) )
+ {
+ a->a_next = NULL;
+ attr_free( a_hasSubordinate );
+ a_hasSubordinate = NULL;
+ }
+
+ if ( a_entryUUID && !( bsi.bsi_flags & BSQL_SF_ALL_OPER )
+ && !ad_inlist( slap_schema.si_ad_entryUUID, op->ors_attrs ) )
+ {
a->a_next = NULL;
- attr_free( hasSubordinate );
- hasSubordinate = NULL;
+ attr_free( a_hasSubordinate );
+ a_hasSubordinate = NULL;
}
+#endif
rs->sr_attrs = op->ors_attrs;
rs->sr_operational_attrs = NULL;
#include "slap.h"
#include "proto-sql.h"
+#include "lutil.h"
#define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
#define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
return 0;
}
+int
+backsql_entryUUID(
+ backsql_info *bi,
+ backsql_entryID *id,
+ struct berval *entryUUID,
+ void *memctx )
+{
+ char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
+ struct berval uuid;
+#ifdef BACKSQL_ARBITRARY_KEY
+ int i;
+ ber_len_t l, lmax;
+#endif /* BACKSQL_ARBITRARY_KEY */
+
+ /* entryUUID is generated as "%08x-%04x-%04x-0000-eaddrXXX"
+ * with eid_oc_id as %08x and hi and lo eid_id as %04x-%04x */
+ assert( bi );
+ assert( id );
+ assert( entryUUID );
+
+#ifdef BACKSQL_ARBITRARY_KEY
+ snprintf( uuidbuf, sizeof( uuidbuf ),
+ "%08x-0000-0000-0000-000000000000",
+ ( id->eid_oc_id & 0xFFFFFFFF ) );
+ lmax = id->eid_keyval.bv_len < 12 ? id->eid_keyval.bv_len : 12;
+ for ( l = 0, i = 9; l < lmax; l++, i += 2 ) {
+ switch ( i ) {
+ case STRLENOF( "00000000-0000" ):
+ case STRLENOF( "00000000-0000-0000" ):
+ case STRLENOF( "00000000-0000-0000-0000" ):
+ uuidbuf[ i++ ] = '-';
+ /* FALLTHRU */
+
+ default:
+ snprintf( &uuidbuf[ i ], 3, "%2x", id->eid_keyval.bv_val[ l ] );
+ break;
+ }
+ }
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ /* note: works only with 32 bit architectures... */
+ snprintf( uuidbuf, sizeof( uuidbuf ),
+ "%08x-%04x-%04x-0000-000000000000",
+ ( id->eid_oc_id & 0xFFFFFFFF ),
+ ( ( id->eid_keyval & 0xFFFF0000 ) >> 16 ),
+ ( id->eid_keyval & 0xFFFF ) );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+
+ uuid.bv_val = uuidbuf;
+ uuid.bv_len = strlen( uuidbuf );
+
+ ber_dupbv_x( entryUUID, &uuid, memctx );
+
+ return 0;
+}
+
+int
+backsql_entryUUID_decode(
+ struct berval *entryUUID,
+ unsigned long *oc_id,
+#ifdef BACKSQL_ARBITRARY_KEY
+ struct berval *keyval
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ unsigned long *keyval
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+ )
+{
+ fprintf( stderr, "==> backsql_entryUUID_decode()\n" );
+
+ *oc_id = ( entryUUID->bv_val[0] << 3 )
+ + ( entryUUID->bv_val[1] << 2 )
+ + ( entryUUID->bv_val[2] << 1 )
+ + entryUUID->bv_val[3];
+
+#ifdef BACKSQL_ARBITRARY_KEY
+#else /* ! BACKSQL_ARBITRARY_KEY */
+ *keyval = ( entryUUID->bv_val[4] << 3 )
+ + ( entryUUID->bv_val[5] << 2 )
+ + ( entryUUID->bv_val[6] << 1 )
+ + entryUUID->bv_val[7];
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+
+ fprintf( stderr, "<== backsql_entryUUID_decode(): oc=%lu id=%lu\n",
+ *oc_id, *keyval );
+
+ return LDAP_SUCCESS;
+}
+
+
#endif /* SLAPD_SQL */
-# Testing search...
+# Testing baseobject search...
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example
+dc: example
+
+# Testing onelevel search...
+dn: documentTitle=book1,dc=example,dc=com
+objectClass: document
+description: abstract1
+documentTitle: book1
+documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
+documentAuthor: cn=Torvlobnor Puzdoy,dc=example,dc=com
+documentIdentifier: document 1
+
+dn: documentTitle=book2,dc=example,dc=com
+objectClass: document
+description: abstract2
+documentTitle: book2
+documentAuthor: cn=Mitya Kovalev,dc=example,dc=com
+documentIdentifier: document 2
+
+dn: cn=Mitya Kovalev,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Mitya Kovalev
+sn: Kovalev
+seeAlso: documentTitle=book1,dc=example,dc=com
+seeAlso: documentTitle=book2,dc=example,dc=com
+givenName: Mitya
+telephoneNumber: 222-3234
+telephoneNumber: 332-2334
+
+dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Torvlobnor Puzdoy
+sn: Puzdoy
+seeAlso: documentTitle=book1,dc=example,dc=com
+givenName: Torvlobnor
+telephoneNumber: 545-4563
+
+# refldap://localhost/dc=example,dc=com??one
+
+# Testing subtree search...
dn: documentTitle=book1,dc=example,dc=com
objectClass: document
description: abstract1
# refldap://localhost/dc=example,dc=com??sub
+# Testing entryUUID in filter...
+dn: cn=Mitya Kovalev,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Mitya Kovalev
+sn: Kovalev
+seeAlso: documentTitle=book1,dc=example,dc=com
+seeAlso: documentTitle=book2,dc=example,dc=com
+givenName: Mitya
+telephoneNumber: 222-3234
+telephoneNumber: 332-2334
+
# Testing attribute inheritance in requested attributes...
dn: cn=Mitya Kovalev,dc=example,dc=com
cn: Mitya Kovalev
entryDN: documentTitle=book1,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE
+entryUUID: 00000002-0000-0001-0000-000000000000
dn: documentTitle=book2,dc=example,dc=com
structuralObjectClass: document
entryDN: documentTitle=book2,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE
+entryUUID: 00000002-0000-0002-0000-000000000000
dn: dc=example,dc=com
structuralObjectClass: organization
entryDN: dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: TRUE
+entryUUID: 00000003-0000-0001-0000-000000000000
dn: cn=Mitya Kovalev,dc=example,dc=com
structuralObjectClass: inetOrgPerson
entryDN: cn=Mitya Kovalev,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE
+entryUUID: 00000001-0000-0001-0000-000000000000
dn: cn=Torvlobnor Puzdoy,dc=example,dc=com
structuralObjectClass: inetOrgPerson
entryDN: cn=Torvlobnor Puzdoy,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE
+entryUUID: 00000001-0000-0002-0000-000000000000
# refldap://localhost/dc=example,dc=com??sub
exit $RC
fi
-echo "Testing search..."
-echo "# Testing search..." > $SEARCHOUT
+echo "Testing baseobject search..."
+echo "# Testing baseobject search..." >> $SEARCHOUT
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing onelevel search..."
+echo "# Testing onelevel search..." >> $SEARCHOUT
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" -s one >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing subtree search..."
+echo "# Testing subtree search..." >> $SEARCHOUT
$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" >> $SEARCHOUT 2>&1
RC=$?
exit $RC
fi
+echo "Testing entryUUID in filter..."
+echo "# Testing entryUUID in filter..." >> $SEARCHOUT
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
+ "(entryUUID=00000001-0000-0001-0000-000000000000)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
echo "Testing attribute inheritance in requested attributes..."
echo "# Testing attribute inheritance in requested attributes..." >> $SEARCHOUT
$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
echo "Testing operational attributes in request..."
echo "# Testing operational attributes in request..." >> $SEARCHOUT
$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" \
- '+' >> $SEARCHOUT 2>&1
+ '+' 2>&1 | grep -v '^entryCSN:' >> $SEARCHOUT
RC=$?
if test $RC != 0 ; then