xref: /titanic_54/usr/src/lib/libnisdb/db_table.cc (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	db_table.cc
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <malloc.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>		/* srand48() */
35*7c478bd9Sstevel@tonic-gate #include <lber.h>
36*7c478bd9Sstevel@tonic-gate #include <ldap.h>
37*7c478bd9Sstevel@tonic-gate #include "db_headers.h"
38*7c478bd9Sstevel@tonic-gate #include "db_table.h"
39*7c478bd9Sstevel@tonic-gate #include "db_pickle.h"    /* for dump and load */
40*7c478bd9Sstevel@tonic-gate #include "db_entry.h"
41*7c478bd9Sstevel@tonic-gate #include "nisdb_mt.h"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include "ldap_parse.h"
44*7c478bd9Sstevel@tonic-gate #include "ldap_util.h"
45*7c478bd9Sstevel@tonic-gate #include "ldap_map.h"
46*7c478bd9Sstevel@tonic-gate #include "ldap_xdr.h"
47*7c478bd9Sstevel@tonic-gate #include "nis_hashitem.h"
48*7c478bd9Sstevel@tonic-gate #include "nisdb_ldap.h"
49*7c478bd9Sstevel@tonic-gate #include "nis_parse_ldap_conf.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static time_t	maxTimeT;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * Find the largest (positive) value of time_t.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * If time_t is unsigned, the largest possible value is just ~0.
57*7c478bd9Sstevel@tonic-gate  * However, if it's signed, then ~0 is negative. Since lint (for
58*7c478bd9Sstevel@tonic-gate  * sure), and perhaps the compiler too, dislike comparing an
59*7c478bd9Sstevel@tonic-gate  * unsigned quantity to see if it's less than zero, we compare
60*7c478bd9Sstevel@tonic-gate  * to one instead. If negative, the largest possible value is
61*7c478bd9Sstevel@tonic-gate  * th inverse of 2**(N-1), where N is the number of bits in a
62*7c478bd9Sstevel@tonic-gate  * time_t.
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate extern "C" {
65*7c478bd9Sstevel@tonic-gate static void
66*7c478bd9Sstevel@tonic-gate __setMaxTimeT(void)
67*7c478bd9Sstevel@tonic-gate {
68*7c478bd9Sstevel@tonic-gate 	unsigned char	b[sizeof (time_t)];
69*7c478bd9Sstevel@tonic-gate 	int		i;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	/* Compute ~0 for an unknown length integer */
72*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (time_t); i++) {
73*7c478bd9Sstevel@tonic-gate 		b[i] = 0xff;
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 	/* Set maxTimeT to ~0 of appropriate length */
76*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&maxTimeT, b, sizeof (time_t));
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 	if (maxTimeT < 1)
79*7c478bd9Sstevel@tonic-gate 		maxTimeT = ~(1<<((8*sizeof (maxTimeT))-1));
80*7c478bd9Sstevel@tonic-gate }
81*7c478bd9Sstevel@tonic-gate #pragma init(__setMaxTimeT)
82*7c478bd9Sstevel@tonic-gate }
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /* How much to grow table by */
85*7c478bd9Sstevel@tonic-gate #define	DB_TABLE_GROWTH_INCREMENT 1024
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /* 0'th not used; might be confusing. */
88*7c478bd9Sstevel@tonic-gate #define	DB_TABLE_START 1
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /* prevents wrap around numbers from being passed */
91*7c478bd9Sstevel@tonic-gate #define	CALLOC_LIMIT 536870911
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /* Initial table sizes to use before using 1K increments. */
94*7c478bd9Sstevel@tonic-gate /* This helps conserve memory usage when there are lots of small tables. */
95*7c478bd9Sstevel@tonic-gate static int tabsizes[] = {
96*7c478bd9Sstevel@tonic-gate 	16,
97*7c478bd9Sstevel@tonic-gate 	128,
98*7c478bd9Sstevel@tonic-gate 	512,
99*7c478bd9Sstevel@tonic-gate 	DB_TABLE_GROWTH_INCREMENT,
100*7c478bd9Sstevel@tonic-gate 	0
101*7c478bd9Sstevel@tonic-gate 	};
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /* Returns the next size to use for table */
104*7c478bd9Sstevel@tonic-gate static long unsigned
105*7c478bd9Sstevel@tonic-gate get_new_table_size(long unsigned oldsize)
106*7c478bd9Sstevel@tonic-gate {
107*7c478bd9Sstevel@tonic-gate 	long unsigned newsize = 0, n;
108*7c478bd9Sstevel@tonic-gate 	if (oldsize == 0)
109*7c478bd9Sstevel@tonic-gate 		newsize = tabsizes[0];
110*7c478bd9Sstevel@tonic-gate 	else {
111*7c478bd9Sstevel@tonic-gate 		for (n = 0; newsize = tabsizes[n++]; )
112*7c478bd9Sstevel@tonic-gate 			if (oldsize == newsize) {
113*7c478bd9Sstevel@tonic-gate 				newsize = tabsizes[n];	/* get next size */
114*7c478bd9Sstevel@tonic-gate 				break;
115*7c478bd9Sstevel@tonic-gate 			}
116*7c478bd9Sstevel@tonic-gate 		if (newsize == 0)
117*7c478bd9Sstevel@tonic-gate 			newsize = oldsize + DB_TABLE_GROWTH_INCREMENT;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 	return (newsize);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /* destructor */
124*7c478bd9Sstevel@tonic-gate db_free_list::~db_free_list()
125*7c478bd9Sstevel@tonic-gate {
126*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::~db_free_list");
127*7c478bd9Sstevel@tonic-gate 	reset();   /* free list entries */
128*7c478bd9Sstevel@tonic-gate 	DESTROYRW(free_list);
129*7c478bd9Sstevel@tonic-gate }
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate void
132*7c478bd9Sstevel@tonic-gate db_free_list::reset()
133*7c478bd9Sstevel@tonic-gate {
134*7c478bd9Sstevel@tonic-gate 	db_free_entry *current, *nextentry;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::reset");
137*7c478bd9Sstevel@tonic-gate 	for (current = head; current != NULL; ) {
138*7c478bd9Sstevel@tonic-gate 		nextentry = current->next;
139*7c478bd9Sstevel@tonic-gate 		delete current;
140*7c478bd9Sstevel@tonic-gate 		current = nextentry;
141*7c478bd9Sstevel@tonic-gate 	}
142*7c478bd9Sstevel@tonic-gate 	head = NULL;
143*7c478bd9Sstevel@tonic-gate 	count = 0;
144*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_free_list::reset");
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /* Returns the location of a free entry, or NULL, if there aren't any. */
148*7c478bd9Sstevel@tonic-gate entryp
149*7c478bd9Sstevel@tonic-gate db_free_list::pop()
150*7c478bd9Sstevel@tonic-gate {
151*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, NULL, "w db_free_list::pop");
152*7c478bd9Sstevel@tonic-gate 	if (head == NULL) {
153*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL, "wu db_free_list::pop");
154*7c478bd9Sstevel@tonic-gate 		return (NULL);
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 	db_free_entry* old_head = head;
157*7c478bd9Sstevel@tonic-gate 	entryp found = head->where;
158*7c478bd9Sstevel@tonic-gate 	head = head->next;
159*7c478bd9Sstevel@tonic-gate 	delete old_head;
160*7c478bd9Sstevel@tonic-gate 	--count;
161*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, found, "wu db_free_list::pop");
162*7c478bd9Sstevel@tonic-gate 	return (found);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate  * Adds given location to the free list.
167*7c478bd9Sstevel@tonic-gate  * Returns TRUE if successful, FALSE otherwise (when out of memory).
168*7c478bd9Sstevel@tonic-gate */
169*7c478bd9Sstevel@tonic-gate bool_t
170*7c478bd9Sstevel@tonic-gate db_free_list::push(entryp tabloc)
171*7c478bd9Sstevel@tonic-gate {
172*7c478bd9Sstevel@tonic-gate 	db_free_entry * newentry = new db_free_entry;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db_free_list::push");
175*7c478bd9Sstevel@tonic-gate 	if (newentry == NULL) {
176*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db_free_list::push");
177*7c478bd9Sstevel@tonic-gate 	    FATAL3("db_free_list::push: cannot allocation space",
178*7c478bd9Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, FALSE);
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 	newentry->where = tabloc;
181*7c478bd9Sstevel@tonic-gate 	newentry->next = head;
182*7c478bd9Sstevel@tonic-gate 	head = newentry;
183*7c478bd9Sstevel@tonic-gate 	++count;
184*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, TRUE, "wu db_free_list::push");
185*7c478bd9Sstevel@tonic-gate 	return (TRUE);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate /*
189*7c478bd9Sstevel@tonic-gate  * Returns in a vector the information in the free list.
190*7c478bd9Sstevel@tonic-gate  * Vector returned is of form: [n free cells][n1][n2][loc1], ..[locn].
191*7c478bd9Sstevel@tonic-gate  * Leave the first 'n' cells free.
192*7c478bd9Sstevel@tonic-gate  * n1 is the number of entries that should be in the freelist.
193*7c478bd9Sstevel@tonic-gate  * n2 is the number of entries actually found in the freelist.
194*7c478bd9Sstevel@tonic-gate  * [loc1...locn] are the entries.   n2 <= n1 because we never count beyond n1.
195*7c478bd9Sstevel@tonic-gate  * It is up to the caller to free the returned vector when he is through.
196*7c478bd9Sstevel@tonic-gate */
197*7c478bd9Sstevel@tonic-gate long *
198*7c478bd9Sstevel@tonic-gate db_free_list::stats(int nslots)
199*7c478bd9Sstevel@tonic-gate {
200*7c478bd9Sstevel@tonic-gate 	long	realcount = 0,
201*7c478bd9Sstevel@tonic-gate 		i,
202*7c478bd9Sstevel@tonic-gate 		liststart = nslots,		// start of freelist
203*7c478bd9Sstevel@tonic-gate 		listend = nslots+count+2;	// end of freelist
204*7c478bd9Sstevel@tonic-gate 	db_free_entry_p current = head;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_free_list::stats");
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	long *answer = (long *)malloc((int)(listend)*sizeof (long));
209*7c478bd9Sstevel@tonic-gate 	if (answer == 0) {
210*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_free_list::stats");
211*7c478bd9Sstevel@tonic-gate 		FATAL3("db_free_list::stats:  cannot allocation space",
212*7c478bd9Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, NULL);
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	answer[liststart] = count;  /* size of freelist */
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	for (i = liststart+2; i < listend && current != NULL; i++) {
218*7c478bd9Sstevel@tonic-gate 		answer[i] = current->where;
219*7c478bd9Sstevel@tonic-gate 		current = current->next;
220*7c478bd9Sstevel@tonic-gate 		++realcount;
221*7c478bd9Sstevel@tonic-gate 	}
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	answer[liststart+1] = realcount;
224*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, answer, "ru db_free_list::stats");
225*7c478bd9Sstevel@tonic-gate 	return (answer);
226*7c478bd9Sstevel@tonic-gate }
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate /* Set default values for the mapping structure */
230*7c478bd9Sstevel@tonic-gate void
231*7c478bd9Sstevel@tonic-gate db_table::initMappingStruct(__nisdb_table_mapping_t *m) {
232*7c478bd9Sstevel@tonic-gate 	if (m == 0)
233*7c478bd9Sstevel@tonic-gate 		return;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	m->initTtlLo = (ldapDBTableMapping.initTtlLo > 0) ?
236*7c478bd9Sstevel@tonic-gate 			ldapDBTableMapping.initTtlLo : (3600-1800);
237*7c478bd9Sstevel@tonic-gate 	m->initTtlHi = (ldapDBTableMapping.initTtlHi > 0) ?
238*7c478bd9Sstevel@tonic-gate 			ldapDBTableMapping.initTtlHi : (3600+1800);
239*7c478bd9Sstevel@tonic-gate 	m->ttl = (ldapDBTableMapping.ttl > 0) ?
240*7c478bd9Sstevel@tonic-gate 			ldapDBTableMapping.ttl : 3600;
241*7c478bd9Sstevel@tonic-gate 	m->enumExpire = 0;
242*7c478bd9Sstevel@tonic-gate 	m->fromLDAP = FALSE;
243*7c478bd9Sstevel@tonic-gate 	m->toLDAP = FALSE;
244*7c478bd9Sstevel@tonic-gate 	m->isMaster = FALSE;
245*7c478bd9Sstevel@tonic-gate 	m->retrieveError = ldapDBTableMapping.retrieveError;
246*7c478bd9Sstevel@tonic-gate 	m->retrieveErrorRetry.attempts =
247*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.retrieveErrorRetry.attempts;
248*7c478bd9Sstevel@tonic-gate 	m->retrieveErrorRetry.timeout =
249*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.retrieveErrorRetry.timeout;
250*7c478bd9Sstevel@tonic-gate 	m->storeError = ldapDBTableMapping.storeError;
251*7c478bd9Sstevel@tonic-gate 	m->storeErrorRetry.attempts =
252*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.storeErrorRetry.attempts;
253*7c478bd9Sstevel@tonic-gate 	m->storeErrorRetry.timeout =
254*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.storeErrorRetry.timeout;
255*7c478bd9Sstevel@tonic-gate 	m->storeErrorDisp = ldapDBTableMapping.storeErrorDisp;
256*7c478bd9Sstevel@tonic-gate 	m->refreshError = ldapDBTableMapping.refreshError;
257*7c478bd9Sstevel@tonic-gate 	m->refreshErrorRetry.attempts =
258*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.refreshErrorRetry.attempts;
259*7c478bd9Sstevel@tonic-gate 	m->refreshErrorRetry.timeout =
260*7c478bd9Sstevel@tonic-gate 		ldapDBTableMapping.refreshErrorRetry.timeout;
261*7c478bd9Sstevel@tonic-gate 	m->matchFetch = ldapDBTableMapping.matchFetch;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (mapping.expire != 0)
264*7c478bd9Sstevel@tonic-gate 		free(mapping.expire);
265*7c478bd9Sstevel@tonic-gate 	m->expire = 0;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (m->tm != 0)
268*7c478bd9Sstevel@tonic-gate 		free(m->tm);
269*7c478bd9Sstevel@tonic-gate 	m->tm = 0;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	/*
272*7c478bd9Sstevel@tonic-gate 	 * The 'objType' field obviously indicates the type of object.
273*7c478bd9Sstevel@tonic-gate 	 * However, we also use it to tell us if we've retrieved mapping
274*7c478bd9Sstevel@tonic-gate 	 * data from LDAP or not; in the latter case, 'objType' is
275*7c478bd9Sstevel@tonic-gate 	 * NIS_BOGUS_OBJ. For purposes of maintaining expiration times,
276*7c478bd9Sstevel@tonic-gate 	 * we may need to know if the object is a table or a directory
277*7c478bd9Sstevel@tonic-gate 	 * _before_ we've retrieved any mapping data. Hence the 'expireType'
278*7c478bd9Sstevel@tonic-gate 	 * field, which starts as NIS_BOGUS_OBJ (meaning, don't know, assume
279*7c478bd9Sstevel@tonic-gate 	 * directory for now), and later is set to NIS_DIRECTORY_OBJ
280*7c478bd9Sstevel@tonic-gate 	 * (always keep expiration data, in case one of the dir entries
281*7c478bd9Sstevel@tonic-gate 	 * is mapped) or NIS_TABLE_OBJ (only need expiration data if
282*7c478bd9Sstevel@tonic-gate 	 * tha table is mapped).
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	m->objType = NIS_BOGUS_OBJ;
285*7c478bd9Sstevel@tonic-gate 	m->expireType = NIS_BOGUS_OBJ;
286*7c478bd9Sstevel@tonic-gate 	if (m->objName != 0)
287*7c478bd9Sstevel@tonic-gate 		free(m->objName);
288*7c478bd9Sstevel@tonic-gate 	m->objName = 0;
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate void
292*7c478bd9Sstevel@tonic-gate db_table::db_table_ldap_init(void) {
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	INITRW(table);
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	enumMode.flag = 0;
297*7c478bd9Sstevel@tonic-gate 	enumCount.flag = 0;
298*7c478bd9Sstevel@tonic-gate 	enumIndex.ptr = 0;
299*7c478bd9Sstevel@tonic-gate 	enumArray.ptr = 0;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	mapping.expire = 0;
302*7c478bd9Sstevel@tonic-gate 	mapping.tm = 0;
303*7c478bd9Sstevel@tonic-gate 	mapping.objName = 0;
304*7c478bd9Sstevel@tonic-gate 	mapping.isDeferredTable = FALSE;
305*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&mapping.enumLock, 0, 0);
306*7c478bd9Sstevel@tonic-gate 	mapping.enumTid = 0;
307*7c478bd9Sstevel@tonic-gate 	mapping.enumStat = -1;
308*7c478bd9Sstevel@tonic-gate 	mapping.enumDeferred = 0;
309*7c478bd9Sstevel@tonic-gate 	mapping.enumEntries = 0;
310*7c478bd9Sstevel@tonic-gate 	mapping.enumTime = 0;
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate /* db_table constructor */
314*7c478bd9Sstevel@tonic-gate db_table::db_table() : freelist()
315*7c478bd9Sstevel@tonic-gate {
316*7c478bd9Sstevel@tonic-gate 	tab = NULL;
317*7c478bd9Sstevel@tonic-gate 	table_size = 0;
318*7c478bd9Sstevel@tonic-gate 	last_used = 0;
319*7c478bd9Sstevel@tonic-gate 	count = 0;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	db_table_ldap_init();
322*7c478bd9Sstevel@tonic-gate 	initMappingStruct(&mapping);
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate /*  grow(); */
325*7c478bd9Sstevel@tonic-gate }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*
328*7c478bd9Sstevel@tonic-gate  * db_table destructor:
329*7c478bd9Sstevel@tonic-gate  * 1.  Get rid of contents of freelist
330*7c478bd9Sstevel@tonic-gate  * 2.  delete all entries hanging off table
331*7c478bd9Sstevel@tonic-gate  * 3.  get rid of table itself
332*7c478bd9Sstevel@tonic-gate */
333*7c478bd9Sstevel@tonic-gate db_table::~db_table()
334*7c478bd9Sstevel@tonic-gate {
335*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::~db_table");
336*7c478bd9Sstevel@tonic-gate 	reset();
337*7c478bd9Sstevel@tonic-gate 	DESTROYRW(table);
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate /* reset size and pointers */
341*7c478bd9Sstevel@tonic-gate void
342*7c478bd9Sstevel@tonic-gate db_table::reset()
343*7c478bd9Sstevel@tonic-gate {
344*7c478bd9Sstevel@tonic-gate 	int i, done = 0;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::reset");
347*7c478bd9Sstevel@tonic-gate 	freelist.reset();
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	/* Add sanity check in case of table corruption */
350*7c478bd9Sstevel@tonic-gate 	if (tab != NULL) {
351*7c478bd9Sstevel@tonic-gate 		for (i = 0;
352*7c478bd9Sstevel@tonic-gate 			i <= last_used && i < table_size && done < count;
353*7c478bd9Sstevel@tonic-gate 			i++) {
354*7c478bd9Sstevel@tonic-gate 			if (tab[i]) {
355*7c478bd9Sstevel@tonic-gate 				free_entry(tab[i]);
356*7c478bd9Sstevel@tonic-gate 				++done;
357*7c478bd9Sstevel@tonic-gate 			}
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	delete tab;
362*7c478bd9Sstevel@tonic-gate 	table_size = last_used = count = 0;
363*7c478bd9Sstevel@tonic-gate 	tab = NULL;
364*7c478bd9Sstevel@tonic-gate 	sfree(mapping.expire);
365*7c478bd9Sstevel@tonic-gate 	mapping.expire = NULL;
366*7c478bd9Sstevel@tonic-gate 	mapping.objType = NIS_BOGUS_OBJ;
367*7c478bd9Sstevel@tonic-gate 	mapping.expireType = NIS_BOGUS_OBJ;
368*7c478bd9Sstevel@tonic-gate 	sfree(mapping.objName);
369*7c478bd9Sstevel@tonic-gate 	mapping.objName = 0;
370*7c478bd9Sstevel@tonic-gate 	/* Leave other values of the mapping structure unchanged */
371*7c478bd9Sstevel@tonic-gate 	enumMode.flag = 0;
372*7c478bd9Sstevel@tonic-gate 	enumCount.flag = 0;
373*7c478bd9Sstevel@tonic-gate 	sfree(enumIndex.ptr);
374*7c478bd9Sstevel@tonic-gate 	enumIndex.ptr = 0;
375*7c478bd9Sstevel@tonic-gate 	sfree(enumArray.ptr);
376*7c478bd9Sstevel@tonic-gate 	enumArray.ptr = 0;
377*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_table::reset");
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate db_status
381*7c478bd9Sstevel@tonic-gate db_table::allocateExpire(long oldSize, long newSize) {
382*7c478bd9Sstevel@tonic-gate 	time_t			*newExpire;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	newExpire = (time_t *)realloc(mapping.expire,
385*7c478bd9Sstevel@tonic-gate 				newSize * sizeof (mapping.expire[0]));
386*7c478bd9Sstevel@tonic-gate 	if (newExpire != NULL) {
387*7c478bd9Sstevel@tonic-gate 		/* Initialize new portion */
388*7c478bd9Sstevel@tonic-gate 		(void) memset(&newExpire[oldSize], 0,
389*7c478bd9Sstevel@tonic-gate 				(newSize-oldSize) * sizeof (newExpire[0]));
390*7c478bd9Sstevel@tonic-gate 		mapping.expire = newExpire;
391*7c478bd9Sstevel@tonic-gate 	} else {
392*7c478bd9Sstevel@tonic-gate 		return (DB_MEMORY_LIMIT);
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
396*7c478bd9Sstevel@tonic-gate }
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate db_status
399*7c478bd9Sstevel@tonic-gate db_table::allocateEnumArray(long oldSize, long newSize) {
400*7c478bd9Sstevel@tonic-gate 	entry_object	**newEnumArray;
401*7c478bd9Sstevel@tonic-gate 	char		*myself = "db_table::allocateEnumArray";
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	if (enumCount.flag > 0) {
404*7c478bd9Sstevel@tonic-gate 		if (enumIndex.ptr == 0) {
405*7c478bd9Sstevel@tonic-gate 			enumIndex.ptr = (entryp *)am(myself, enumCount.flag *
406*7c478bd9Sstevel@tonic-gate 						sizeof (entryp));
407*7c478bd9Sstevel@tonic-gate 			if (enumIndex.ptr == 0)
408*7c478bd9Sstevel@tonic-gate 				return (DB_MEMORY_LIMIT);
409*7c478bd9Sstevel@tonic-gate 		}
410*7c478bd9Sstevel@tonic-gate 		oldSize = 0;
411*7c478bd9Sstevel@tonic-gate 		newSize = enumCount.flag;
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 	newEnumArray = (entry_object **)realloc(enumArray.ptr,
414*7c478bd9Sstevel@tonic-gate 			newSize * sizeof (entry_object *));
415*7c478bd9Sstevel@tonic-gate 	if (newEnumArray != 0 && newSize > oldSize) {
416*7c478bd9Sstevel@tonic-gate 		(void) memcpy(&newEnumArray[oldSize], &tab[oldSize],
417*7c478bd9Sstevel@tonic-gate 			(newSize-oldSize) * sizeof (entry_object *));
418*7c478bd9Sstevel@tonic-gate 		enumArray.ptr = newEnumArray;
419*7c478bd9Sstevel@tonic-gate 	} else if (newEnumArray == 0) {
420*7c478bd9Sstevel@tonic-gate 		return (DB_MEMORY_LIMIT);
421*7c478bd9Sstevel@tonic-gate 	}
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate /* Expand the table.  Fatal error if insufficient memory. */
427*7c478bd9Sstevel@tonic-gate void
428*7c478bd9Sstevel@tonic-gate db_table::grow()
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::grow");
431*7c478bd9Sstevel@tonic-gate 	long oldsize = table_size;
432*7c478bd9Sstevel@tonic-gate 	entry_object_p *oldtab = tab;
433*7c478bd9Sstevel@tonic-gate 	long i;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	table_size = get_new_table_size(oldsize);
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
438*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "db_table GROWING to %d\n", table_size);
439*7c478bd9Sstevel@tonic-gate #endif
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	if (table_size > CALLOC_LIMIT) {
442*7c478bd9Sstevel@tonic-gate 		table_size = oldsize;
443*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCKV(this, "wu db_table::grow");
444*7c478bd9Sstevel@tonic-gate 		FATAL("db_table::grow: table size exceeds calloc limit",
445*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate //  if ((tab = new entry_object_p[table_size]) == NULL)
449*7c478bd9Sstevel@tonic-gate 	if ((tab = (entry_object_p*)
450*7c478bd9Sstevel@tonic-gate 		calloc((unsigned int) table_size,
451*7c478bd9Sstevel@tonic-gate 			sizeof (entry_object_p))) == NULL) {
452*7c478bd9Sstevel@tonic-gate 		tab = oldtab;		// restore previous table info
453*7c478bd9Sstevel@tonic-gate 		table_size = oldsize;
454*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCKV(this, "wu db_table::grow");
455*7c478bd9Sstevel@tonic-gate 		FATAL("db_table::grow: cannot allocate space", DB_MEMORY_LIMIT);
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	/*
459*7c478bd9Sstevel@tonic-gate 	 * For directories, we may need the expire time array even if the
460*7c478bd9Sstevel@tonic-gate 	 * directory itself isn't mapped. If the objType and expireType both
461*7c478bd9Sstevel@tonic-gate 	 * are bogus, we don't  know yet if this is a table or a directory,
462*7c478bd9Sstevel@tonic-gate 	 * and must proceed accordingly.
463*7c478bd9Sstevel@tonic-gate 	 */
464*7c478bd9Sstevel@tonic-gate 	if (mapping.objType == NIS_DIRECTORY_OBJ ||
465*7c478bd9Sstevel@tonic-gate 			mapping.expireType != NIS_TABLE_OBJ ||
466*7c478bd9Sstevel@tonic-gate 			mapping.fromLDAP) {
467*7c478bd9Sstevel@tonic-gate 		db_status stat = allocateExpire(oldsize, table_size);
468*7c478bd9Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
469*7c478bd9Sstevel@tonic-gate 			free(tab);
470*7c478bd9Sstevel@tonic-gate 			tab = oldtab;
471*7c478bd9Sstevel@tonic-gate 			table_size = oldsize;
472*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCKV(this, "wu db_table::grow expire");
473*7c478bd9Sstevel@tonic-gate 			FATAL(
474*7c478bd9Sstevel@tonic-gate 		"db_table::grow: cannot allocate space for expire", stat);
475*7c478bd9Sstevel@tonic-gate 		}
476*7c478bd9Sstevel@tonic-gate 	}
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	if (oldtab != NULL) {
479*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < oldsize; i++) { // transfer old to new
480*7c478bd9Sstevel@tonic-gate 			tab[i] = oldtab[i];
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 		delete oldtab;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag) {
486*7c478bd9Sstevel@tonic-gate 		db_status stat = allocateEnumArray(oldsize, table_size);
487*7c478bd9Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
488*7c478bd9Sstevel@tonic-gate 			free(tab);
489*7c478bd9Sstevel@tonic-gate 			tab = oldtab;
490*7c478bd9Sstevel@tonic-gate 			table_size = oldsize;
491*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCKV(this, "wu db_table::grow enumArray");
492*7c478bd9Sstevel@tonic-gate 			FATAL(
493*7c478bd9Sstevel@tonic-gate 		"db_table::grow: cannot allocate space for enumArray", stat);
494*7c478bd9Sstevel@tonic-gate 		}
495*7c478bd9Sstevel@tonic-gate 	}
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_table::grow");
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate /*
501*7c478bd9Sstevel@tonic-gate  * Return the first entry in table, also return its position in
502*7c478bd9Sstevel@tonic-gate  * 'where'.  Return NULL in both if no next entry is found.
503*7c478bd9Sstevel@tonic-gate  */
504*7c478bd9Sstevel@tonic-gate entry_object*
505*7c478bd9Sstevel@tonic-gate db_table::first_entry(entryp * where)
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	ASSERTRHELD(table);
508*7c478bd9Sstevel@tonic-gate 	if (count == 0 || tab == NULL) {  /* empty table */
509*7c478bd9Sstevel@tonic-gate 		*where = NULL;
510*7c478bd9Sstevel@tonic-gate 		return (NULL);
511*7c478bd9Sstevel@tonic-gate 	} else {
512*7c478bd9Sstevel@tonic-gate 		entryp i;
513*7c478bd9Sstevel@tonic-gate 		for (i = DB_TABLE_START;
514*7c478bd9Sstevel@tonic-gate 			i < table_size && i <= last_used; i++) {
515*7c478bd9Sstevel@tonic-gate 			if (tab[i] != NULL) {
516*7c478bd9Sstevel@tonic-gate 				*where = i;
517*7c478bd9Sstevel@tonic-gate 				return (tab[i]);
518*7c478bd9Sstevel@tonic-gate 			}
519*7c478bd9Sstevel@tonic-gate 		}
520*7c478bd9Sstevel@tonic-gate 	}
521*7c478bd9Sstevel@tonic-gate 	*where = NULL;
522*7c478bd9Sstevel@tonic-gate 	return (NULL);
523*7c478bd9Sstevel@tonic-gate }
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate /*
526*7c478bd9Sstevel@tonic-gate  * Return the next entry in table from 'prev', also return its position in
527*7c478bd9Sstevel@tonic-gate  * 'newentry'.  Return NULL in both if no next entry is found.
528*7c478bd9Sstevel@tonic-gate  */
529*7c478bd9Sstevel@tonic-gate entry_object *
530*7c478bd9Sstevel@tonic-gate db_table::next_entry(entryp prev, entryp* newentry)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	long i;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	ASSERTRHELD(table);
535*7c478bd9Sstevel@tonic-gate 	if (prev >= table_size || tab == NULL || tab[prev] == NULL)
536*7c478bd9Sstevel@tonic-gate 		return (NULL);
537*7c478bd9Sstevel@tonic-gate 	for (i = prev+1; i < table_size && i <= last_used; i++) {
538*7c478bd9Sstevel@tonic-gate 		if (tab[i] != NULL) {
539*7c478bd9Sstevel@tonic-gate 			*newentry = i;
540*7c478bd9Sstevel@tonic-gate 			return (tab[i]);
541*7c478bd9Sstevel@tonic-gate 		}
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 	*newentry = NULL;
544*7c478bd9Sstevel@tonic-gate 	return (NULL);
545*7c478bd9Sstevel@tonic-gate }
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate /* Return entry at location 'where', NULL if location is invalid. */
548*7c478bd9Sstevel@tonic-gate entry_object *
549*7c478bd9Sstevel@tonic-gate db_table::get_entry(entryp where)
550*7c478bd9Sstevel@tonic-gate {
551*7c478bd9Sstevel@tonic-gate 	ASSERTRHELD(table);
552*7c478bd9Sstevel@tonic-gate 	if (where < table_size && tab != NULL && tab[where] != NULL)
553*7c478bd9Sstevel@tonic-gate 		return (tab[where]);
554*7c478bd9Sstevel@tonic-gate 	else
555*7c478bd9Sstevel@tonic-gate 		return (NULL);
556*7c478bd9Sstevel@tonic-gate }
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate void
559*7c478bd9Sstevel@tonic-gate db_table::setEntryExp(entryp where, entry_obj *obj, int initialLoad) {
560*7c478bd9Sstevel@tonic-gate 	nis_object		*o;
561*7c478bd9Sstevel@tonic-gate 	char			*myself = "db_table::setEntryExp";
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	/*
564*7c478bd9Sstevel@tonic-gate 	 * If we don't know what type of object this is yet, we
565*7c478bd9Sstevel@tonic-gate 	 * can find out now. If it's a directory, the pseudo-object
566*7c478bd9Sstevel@tonic-gate 	 * in column zero will have the type "IN_DIRECTORY";
567*7c478bd9Sstevel@tonic-gate 	 * otherwise, it's a table object.
568*7c478bd9Sstevel@tonic-gate 	 */
569*7c478bd9Sstevel@tonic-gate 	if (mapping.expireType == NIS_BOGUS_OBJ) {
570*7c478bd9Sstevel@tonic-gate 		if (obj != 0) {
571*7c478bd9Sstevel@tonic-gate 			if (obj->en_type != 0 &&
572*7c478bd9Sstevel@tonic-gate 				strcmp(obj->en_type, "IN_DIRECTORY") == 0) {
573*7c478bd9Sstevel@tonic-gate 				mapping.expireType = NIS_DIRECTORY_OBJ;
574*7c478bd9Sstevel@tonic-gate 			} else {
575*7c478bd9Sstevel@tonic-gate 				mapping.expireType = NIS_TABLE_OBJ;
576*7c478bd9Sstevel@tonic-gate 				if (!mapping.fromLDAP) {
577*7c478bd9Sstevel@tonic-gate 					free(mapping.expire);
578*7c478bd9Sstevel@tonic-gate 					mapping.expire = 0;
579*7c478bd9Sstevel@tonic-gate 				}
580*7c478bd9Sstevel@tonic-gate 			}
581*7c478bd9Sstevel@tonic-gate 		}
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/* Set the entry TTL */
585*7c478bd9Sstevel@tonic-gate 	if (mapping.expire != NULL) {
586*7c478bd9Sstevel@tonic-gate 		struct timeval	now;
587*7c478bd9Sstevel@tonic-gate 		time_t		lo, hi, ttl;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&now, NULL);
590*7c478bd9Sstevel@tonic-gate 		if (mapping.expireType == NIS_TABLE_OBJ) {
591*7c478bd9Sstevel@tonic-gate 			lo = mapping.initTtlLo;
592*7c478bd9Sstevel@tonic-gate 			hi = mapping.initTtlHi;
593*7c478bd9Sstevel@tonic-gate 			ttl = mapping.ttl;
594*7c478bd9Sstevel@tonic-gate 			/* TTL == 0 means always expired */
595*7c478bd9Sstevel@tonic-gate 			if (ttl == 0)
596*7c478bd9Sstevel@tonic-gate 				ttl = -1;
597*7c478bd9Sstevel@tonic-gate 		} else {
598*7c478bd9Sstevel@tonic-gate 			__nis_table_mapping_t	*t = 0;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 			o = unmakePseudoEntryObj(obj, 0);
601*7c478bd9Sstevel@tonic-gate 			if (o != 0) {
602*7c478bd9Sstevel@tonic-gate 				__nis_buffer_t	b = {0, 0};
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 				bp2buf(myself, &b, "%s.%s",
605*7c478bd9Sstevel@tonic-gate 					o->zo_name, o->zo_domain);
606*7c478bd9Sstevel@tonic-gate 				t = getObjMapping(b.buf, 0, 1, 0, 0);
607*7c478bd9Sstevel@tonic-gate 				sfree(b.buf);
608*7c478bd9Sstevel@tonic-gate 				nis_destroy_object(o);
609*7c478bd9Sstevel@tonic-gate 			}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 			if (t != 0) {
612*7c478bd9Sstevel@tonic-gate 				lo = t->initTtlLo;
613*7c478bd9Sstevel@tonic-gate 				hi = t->initTtlHi;
614*7c478bd9Sstevel@tonic-gate 				ttl = t->ttl;
615*7c478bd9Sstevel@tonic-gate 				/* TTL == 0 means always expired */
616*7c478bd9Sstevel@tonic-gate 				if (ttl == 0)
617*7c478bd9Sstevel@tonic-gate 					ttl = -1;
618*7c478bd9Sstevel@tonic-gate 			} else {
619*7c478bd9Sstevel@tonic-gate 				/*
620*7c478bd9Sstevel@tonic-gate 				 * No expiration time initialization
621*7c478bd9Sstevel@tonic-gate 				 * data. Cook up values that will
622*7c478bd9Sstevel@tonic-gate 				 * result in mapping.expire[where]
623*7c478bd9Sstevel@tonic-gate 				 * set to maxTimeT.
624*7c478bd9Sstevel@tonic-gate 				 */
625*7c478bd9Sstevel@tonic-gate 				hi = lo = ttl = maxTimeT - now.tv_sec;
626*7c478bd9Sstevel@tonic-gate 			}
627*7c478bd9Sstevel@tonic-gate 		}
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 		if (initialLoad) {
630*7c478bd9Sstevel@tonic-gate 			int	interval = hi - lo + 1;
631*7c478bd9Sstevel@tonic-gate 			if (interval <= 1) {
632*7c478bd9Sstevel@tonic-gate 				mapping.expire[where] = now.tv_sec + lo;
633*7c478bd9Sstevel@tonic-gate 			} else {
634*7c478bd9Sstevel@tonic-gate 				srand48(now.tv_sec);
635*7c478bd9Sstevel@tonic-gate 				mapping.expire[where] = now.tv_sec +
636*7c478bd9Sstevel@tonic-gate 							(lrand48() % interval);
637*7c478bd9Sstevel@tonic-gate 			}
638*7c478bd9Sstevel@tonic-gate 			if (mapping.enumExpire == 0 ||
639*7c478bd9Sstevel@tonic-gate 					mapping.expire[where] <
640*7c478bd9Sstevel@tonic-gate 							mapping.enumExpire)
641*7c478bd9Sstevel@tonic-gate 				mapping.enumExpire = mapping.expire[where];
642*7c478bd9Sstevel@tonic-gate 		} else {
643*7c478bd9Sstevel@tonic-gate 			mapping.expire[where] = now.tv_sec + ttl;
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate }
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate /*
649*7c478bd9Sstevel@tonic-gate  * Add given entry to table in first available slot (either look in freelist
650*7c478bd9Sstevel@tonic-gate  * or add to end of table) and return the the position of where the record
651*7c478bd9Sstevel@tonic-gate  * is placed. 'count' is incremented if entry is added. Table may grow
652*7c478bd9Sstevel@tonic-gate  * as a side-effect of the addition. Copy is made of input.
653*7c478bd9Sstevel@tonic-gate */
654*7c478bd9Sstevel@tonic-gate entryp
655*7c478bd9Sstevel@tonic-gate db_table::add_entry(entry_object *obj, int initialLoad) {
656*7c478bd9Sstevel@tonic-gate 	/*
657*7c478bd9Sstevel@tonic-gate 	 * We're returning an index of the table array, so the caller
658*7c478bd9Sstevel@tonic-gate 	 * should hold a lock until done with the index. To save us
659*7c478bd9Sstevel@tonic-gate 	 * the bother of upgrading to a write lock, it might as well
660*7c478bd9Sstevel@tonic-gate 	 * be a write lock to begin with.
661*7c478bd9Sstevel@tonic-gate 	 */
662*7c478bd9Sstevel@tonic-gate 	ASSERTWHELD(table);
663*7c478bd9Sstevel@tonic-gate 	entryp where = freelist.pop();
664*7c478bd9Sstevel@tonic-gate 	if (where == NULL) {				/* empty freelist */
665*7c478bd9Sstevel@tonic-gate 		if (last_used >= (table_size-1))	/* full (> is for 0) */
666*7c478bd9Sstevel@tonic-gate 			grow();
667*7c478bd9Sstevel@tonic-gate 		where = ++last_used;
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 	if (tab != NULL) {
670*7c478bd9Sstevel@tonic-gate 		++count;
671*7c478bd9Sstevel@tonic-gate 		setEntryExp(where, obj, initialLoad);
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 		if (enumMode.flag)
674*7c478bd9Sstevel@tonic-gate 			enumTouch(where);
675*7c478bd9Sstevel@tonic-gate 		tab[where] = new_entry(obj);
676*7c478bd9Sstevel@tonic-gate 		return (where);
677*7c478bd9Sstevel@tonic-gate 	} else {
678*7c478bd9Sstevel@tonic-gate 		return (NULL);
679*7c478bd9Sstevel@tonic-gate 	}
680*7c478bd9Sstevel@tonic-gate }
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate /*
683*7c478bd9Sstevel@tonic-gate  * Replaces object at specified location by given entry.
684*7c478bd9Sstevel@tonic-gate  * Returns TRUE if replacement successful; FALSE otherwise.
685*7c478bd9Sstevel@tonic-gate  * There must something already at the specified location, otherwise,
686*7c478bd9Sstevel@tonic-gate  * replacement fails. Copy is not made of the input.
687*7c478bd9Sstevel@tonic-gate  * The pre-existing entry is freed.
688*7c478bd9Sstevel@tonic-gate  */
689*7c478bd9Sstevel@tonic-gate bool_t
690*7c478bd9Sstevel@tonic-gate db_table::replace_entry(entryp where, entry_object * obj)
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	ASSERTWHELD(table);
693*7c478bd9Sstevel@tonic-gate 	if (where < DB_TABLE_START || where >= table_size ||
694*7c478bd9Sstevel@tonic-gate 	    tab == NULL || tab[where] == NULL)
695*7c478bd9Sstevel@tonic-gate 		return (FALSE);
696*7c478bd9Sstevel@tonic-gate 	/* (Re-)set the entry TTL */
697*7c478bd9Sstevel@tonic-gate 	setEntryExp(where, obj, 0);
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag)
700*7c478bd9Sstevel@tonic-gate 		enumTouch(where);
701*7c478bd9Sstevel@tonic-gate 	free_entry(tab[where]);
702*7c478bd9Sstevel@tonic-gate 	tab[where] = obj;
703*7c478bd9Sstevel@tonic-gate 	return (TRUE);
704*7c478bd9Sstevel@tonic-gate }
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate /*
707*7c478bd9Sstevel@tonic-gate  * Deletes entry at specified location.  Returns TRUE if location is valid;
708*7c478bd9Sstevel@tonic-gate  * FALSE if location is invalid, or the freed location cannot be added to
709*7c478bd9Sstevel@tonic-gate  * the freelist.  'count' is decremented if the deletion occurs.  The object
710*7c478bd9Sstevel@tonic-gate  * at that location is freed.
711*7c478bd9Sstevel@tonic-gate  */
712*7c478bd9Sstevel@tonic-gate bool_t
713*7c478bd9Sstevel@tonic-gate db_table::delete_entry(entryp where)
714*7c478bd9Sstevel@tonic-gate {
715*7c478bd9Sstevel@tonic-gate 	bool_t	ret = TRUE;
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	ASSERTWHELD(table);
718*7c478bd9Sstevel@tonic-gate 	if (where < DB_TABLE_START || where >= table_size ||
719*7c478bd9Sstevel@tonic-gate 	    tab == NULL || tab[where] == NULL)
720*7c478bd9Sstevel@tonic-gate 		return (FALSE);
721*7c478bd9Sstevel@tonic-gate 	if (mapping.expire != NULL) {
722*7c478bd9Sstevel@tonic-gate 		mapping.expire[where] = 0;
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag)
725*7c478bd9Sstevel@tonic-gate 		enumTouch(where);
726*7c478bd9Sstevel@tonic-gate 	free_entry(tab[where]);
727*7c478bd9Sstevel@tonic-gate 	tab[where] = NULL;    /* very important to set it to null */
728*7c478bd9Sstevel@tonic-gate 	--count;
729*7c478bd9Sstevel@tonic-gate 	if (where == last_used) { /* simple case, deleting from end */
730*7c478bd9Sstevel@tonic-gate 		--last_used;
731*7c478bd9Sstevel@tonic-gate 		return (TRUE);
732*7c478bd9Sstevel@tonic-gate 	} else {
733*7c478bd9Sstevel@tonic-gate 		return (freelist.push(where));
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 	return (ret);
736*7c478bd9Sstevel@tonic-gate }
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate /*
739*7c478bd9Sstevel@tonic-gate  * Returns statistics of table.
740*7c478bd9Sstevel@tonic-gate  * [vector_size][table_size][last_used][count][freelist].
741*7c478bd9Sstevel@tonic-gate  * It is up to the caller to free the returned vector when his is through.
742*7c478bd9Sstevel@tonic-gate  * The free list is included if 'fl' is TRUE.
743*7c478bd9Sstevel@tonic-gate */
744*7c478bd9Sstevel@tonic-gate long *
745*7c478bd9Sstevel@tonic-gate db_table::stats(bool_t include_freelist)
746*7c478bd9Sstevel@tonic-gate {
747*7c478bd9Sstevel@tonic-gate 	long *answer;
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_table::stats");
750*7c478bd9Sstevel@tonic-gate 	if (include_freelist)
751*7c478bd9Sstevel@tonic-gate 		answer = freelist.stats(3);
752*7c478bd9Sstevel@tonic-gate 	else {
753*7c478bd9Sstevel@tonic-gate 		answer = (long *)malloc(3*sizeof (long));
754*7c478bd9Sstevel@tonic-gate 	}
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	if (answer) {
757*7c478bd9Sstevel@tonic-gate 		answer[0] = table_size;
758*7c478bd9Sstevel@tonic-gate 		answer[1] = last_used;
759*7c478bd9Sstevel@tonic-gate 		answer[2] = count;
760*7c478bd9Sstevel@tonic-gate 	}
761*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, answer, "ru db_table::stats");
762*7c478bd9Sstevel@tonic-gate 	return (answer);
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate bool_t
766*7c478bd9Sstevel@tonic-gate db_table::configure(char *tablePath) {
767*7c478bd9Sstevel@tonic-gate 	long		i;
768*7c478bd9Sstevel@tonic-gate 	struct timeval	now;
769*7c478bd9Sstevel@tonic-gate 	char		*myself = "db_table::configure";
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&now, NULL);
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "db_table::configure w");
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	/* (Re-)initialize from global info */
776*7c478bd9Sstevel@tonic-gate 	initMappingStruct(&mapping);
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	/* Retrieve table mapping for this table */
779*7c478bd9Sstevel@tonic-gate 	mapping.tm = (__nis_table_mapping_t *)__nis_find_item_mt(
780*7c478bd9Sstevel@tonic-gate 					tablePath, &ldapMappingList, 0, 0);
781*7c478bd9Sstevel@tonic-gate 	if (mapping.tm != 0) {
782*7c478bd9Sstevel@tonic-gate 		__nis_object_dn_t	*odn = mapping.tm->objectDN;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 		/*
785*7c478bd9Sstevel@tonic-gate 		 * The mapping.fromLDAP and mapping.toLDAP fields serve as
786*7c478bd9Sstevel@tonic-gate 		 * quick-references that tell us if mapping is enabled.
787*7c478bd9Sstevel@tonic-gate 		 * Hence, initialize them appropriately from the table
788*7c478bd9Sstevel@tonic-gate 		 * mapping objectDN.
789*7c478bd9Sstevel@tonic-gate 		 */
790*7c478bd9Sstevel@tonic-gate 		while (odn != 0 && (!mapping.fromLDAP || !mapping.toLDAP)) {
791*7c478bd9Sstevel@tonic-gate 			if (odn->read.scope != LDAP_SCOPE_UNKNOWN)
792*7c478bd9Sstevel@tonic-gate 				mapping.fromLDAP = TRUE;
793*7c478bd9Sstevel@tonic-gate 			if (odn->write.scope != LDAP_SCOPE_UNKNOWN)
794*7c478bd9Sstevel@tonic-gate 				mapping.toLDAP = TRUE;
795*7c478bd9Sstevel@tonic-gate 			odn = (__nis_object_dn_t *)odn->next;
796*7c478bd9Sstevel@tonic-gate 		}
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 		/* Set the timeout values */
799*7c478bd9Sstevel@tonic-gate 		mapping.initTtlLo = mapping.tm->initTtlLo;
800*7c478bd9Sstevel@tonic-gate 		mapping.initTtlHi = mapping.tm->initTtlHi;
801*7c478bd9Sstevel@tonic-gate 		mapping.ttl = mapping.tm->ttl;
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 		mapping.objName = sdup(myself, T, mapping.tm->objName);
804*7c478bd9Sstevel@tonic-gate 		if (mapping.objName == 0 && mapping.tm->objName != 0) {
805*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
806*7c478bd9Sstevel@tonic-gate 				"db_table::configure wu objName");
807*7c478bd9Sstevel@tonic-gate 			FATAL3("db_table::configure objName",
808*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, FALSE);
809*7c478bd9Sstevel@tonic-gate 		}
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	/*
813*7c478bd9Sstevel@tonic-gate 	 * In order to initialize the expiration times, we need to know
814*7c478bd9Sstevel@tonic-gate 	 * if 'this' represents a table or a directory. To that end, we
815*7c478bd9Sstevel@tonic-gate 	 * find an entry in the table, and invoke setEntryExp() on it.
816*7c478bd9Sstevel@tonic-gate 	 * As a side effect, setEntryExp() will examine the pseudo-object
817*7c478bd9Sstevel@tonic-gate 	 * in the entry, and set the expireType accordingly.
818*7c478bd9Sstevel@tonic-gate 	 */
819*7c478bd9Sstevel@tonic-gate 	if (tab != 0) {
820*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= last_used; i++) {
821*7c478bd9Sstevel@tonic-gate 			if (tab[i] != NULL) {
822*7c478bd9Sstevel@tonic-gate 				setEntryExp(i, tab[i], 1);
823*7c478bd9Sstevel@tonic-gate 				break;
824*7c478bd9Sstevel@tonic-gate 			}
825*7c478bd9Sstevel@tonic-gate 		}
826*7c478bd9Sstevel@tonic-gate 	}
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	/*
829*7c478bd9Sstevel@tonic-gate 	 * If mapping from an LDAP repository, make sure we have the
830*7c478bd9Sstevel@tonic-gate 	 * expiration time array.
831*7c478bd9Sstevel@tonic-gate 	 */
832*7c478bd9Sstevel@tonic-gate 	if ((mapping.expireType != NIS_TABLE_OBJ || mapping.fromLDAP) &&
833*7c478bd9Sstevel@tonic-gate 			mapping.expire == NULL && table_size > 0 && tab != 0) {
834*7c478bd9Sstevel@tonic-gate 		db_status stat = allocateExpire(0, table_size);
835*7c478bd9Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
836*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
837*7c478bd9Sstevel@tonic-gate 				"db_table::configure wu expire");
838*7c478bd9Sstevel@tonic-gate 			FATAL3("db_table::configure expire",
839*7c478bd9Sstevel@tonic-gate 				stat, FALSE);
840*7c478bd9Sstevel@tonic-gate 		}
841*7c478bd9Sstevel@tonic-gate 	} else if (mapping.expireType == NIS_TABLE_OBJ && !mapping.fromLDAP &&
842*7c478bd9Sstevel@tonic-gate 			mapping.expire != NULL) {
843*7c478bd9Sstevel@tonic-gate 		/* Not using expiration times */
844*7c478bd9Sstevel@tonic-gate 		free(mapping.expire);
845*7c478bd9Sstevel@tonic-gate 		mapping.expire = NULL;
846*7c478bd9Sstevel@tonic-gate 	}
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	/*
849*7c478bd9Sstevel@tonic-gate 	 * Set initial expire times for entries that don't already have one.
850*7c478bd9Sstevel@tonic-gate 	 * Establish the enumeration expiration time to be the minimum of
851*7c478bd9Sstevel@tonic-gate 	 * all expiration times in the table, though no larger than current
852*7c478bd9Sstevel@tonic-gate 	 * time plus initTtlHi.
853*7c478bd9Sstevel@tonic-gate 	 */
854*7c478bd9Sstevel@tonic-gate 	if (mapping.expire != NULL) {
855*7c478bd9Sstevel@tonic-gate 		int	interval = mapping.initTtlHi - mapping.initTtlLo + 1;
856*7c478bd9Sstevel@tonic-gate 		time_t	enumXp = now.tv_sec + mapping.initTtlHi;
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 		if (interval > 1)
859*7c478bd9Sstevel@tonic-gate 			srand48(now.tv_sec);
860*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= last_used; i++) {
861*7c478bd9Sstevel@tonic-gate 			if (tab[i] != NULL && mapping.expire[i] == 0) {
862*7c478bd9Sstevel@tonic-gate 				if (mapping.expireType == NIS_TABLE_OBJ) {
863*7c478bd9Sstevel@tonic-gate 					if (interval > 1)
864*7c478bd9Sstevel@tonic-gate 						mapping.expire[i] =
865*7c478bd9Sstevel@tonic-gate 							now.tv_sec +
866*7c478bd9Sstevel@tonic-gate 							(lrand48() % interval);
867*7c478bd9Sstevel@tonic-gate 					else
868*7c478bd9Sstevel@tonic-gate 						mapping.expire[i] =
869*7c478bd9Sstevel@tonic-gate 							now.tv_sec +
870*7c478bd9Sstevel@tonic-gate 							mapping.initTtlLo;
871*7c478bd9Sstevel@tonic-gate 				} else {
872*7c478bd9Sstevel@tonic-gate 					setEntryExp(i, tab[i], 1);
873*7c478bd9Sstevel@tonic-gate 				}
874*7c478bd9Sstevel@tonic-gate 			}
875*7c478bd9Sstevel@tonic-gate 			if (enumXp > mapping.expire[i])
876*7c478bd9Sstevel@tonic-gate 				enumXp = mapping.expire[i];
877*7c478bd9Sstevel@tonic-gate 		}
878*7c478bd9Sstevel@tonic-gate 		mapping.enumExpire = enumXp;
879*7c478bd9Sstevel@tonic-gate 	}
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "db_table::configure wu");
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	return (TRUE);
884*7c478bd9Sstevel@tonic-gate }
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate /* Return TRUE if the entry at 'loc' hasn't expired */
887*7c478bd9Sstevel@tonic-gate bool_t
888*7c478bd9Sstevel@tonic-gate db_table::cacheValid(entryp loc) {
889*7c478bd9Sstevel@tonic-gate 	bool_t		ret;
890*7c478bd9Sstevel@tonic-gate 	struct timeval	now;
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&now, 0);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	READLOCK(this, FALSE, "db_table::cacheValid r");
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
897*7c478bd9Sstevel@tonic-gate 		ret = FALSE;
898*7c478bd9Sstevel@tonic-gate 	else if (mapping.expire == 0 || mapping.expire[loc] >= now.tv_sec)
899*7c478bd9Sstevel@tonic-gate 		ret = TRUE;
900*7c478bd9Sstevel@tonic-gate 	else
901*7c478bd9Sstevel@tonic-gate 		ret = FALSE;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "db_table::cacheValid ru");
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	return (ret);
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate /*
909*7c478bd9Sstevel@tonic-gate  * If the supplied object has the same content as the one at 'loc',
910*7c478bd9Sstevel@tonic-gate  * update the expiration time for the latter, and return TRUE.
911*7c478bd9Sstevel@tonic-gate  */
912*7c478bd9Sstevel@tonic-gate bool_t
913*7c478bd9Sstevel@tonic-gate db_table::dupEntry(entry_object *obj, entryp loc) {
914*7c478bd9Sstevel@tonic-gate 	if (obj == 0 || loc < 0 || loc >= table_size || tab == 0 ||
915*7c478bd9Sstevel@tonic-gate 			tab[loc] == 0)
916*7c478bd9Sstevel@tonic-gate 		return (FALSE);
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 	if (sameEntry(obj, tab[loc])) {
919*7c478bd9Sstevel@tonic-gate 		setEntryExp(loc, tab[loc], 0);
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 		if (enumMode.flag > 0)
922*7c478bd9Sstevel@tonic-gate 			enumTouch(loc);
923*7c478bd9Sstevel@tonic-gate 		return (TRUE);
924*7c478bd9Sstevel@tonic-gate 	}
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	return (FALSE);
927*7c478bd9Sstevel@tonic-gate }
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate /*
930*7c478bd9Sstevel@tonic-gate  * If enumeration mode is enabled, we keep a shadow array that initially
931*7c478bd9Sstevel@tonic-gate  * starts out the same as 'tab'. Any update activity (add, remove, replace,
932*7c478bd9Sstevel@tonic-gate  * or update timestamp) for an entry in the table means we delete the shadow
933*7c478bd9Sstevel@tonic-gate  * array pointer. When ending enumeration mode, we return the shadow array.
934*7c478bd9Sstevel@tonic-gate  * Any non-NULL entries in the array have not been updated since the start
935*7c478bd9Sstevel@tonic-gate  * of the enum mode.
936*7c478bd9Sstevel@tonic-gate  *
937*7c478bd9Sstevel@tonic-gate  * The indended use is for enumeration of an LDAP container, where we
938*7c478bd9Sstevel@tonic-gate  * will update all entries that currently exist in LDAP. The entries we
939*7c478bd9Sstevel@tonic-gate  * don't update are those that don't exist in LDAP, and thus should be
940*7c478bd9Sstevel@tonic-gate  * removed.
941*7c478bd9Sstevel@tonic-gate  *
942*7c478bd9Sstevel@tonic-gate  * Note that any LDAP query strictly speaking can be a partial enumeration
943*7c478bd9Sstevel@tonic-gate  * (i.e., return more than one match). Since the query might also have
944*7c478bd9Sstevel@tonic-gate  * matched multiple local DB entries, we need to do the same work as for
945*7c478bd9Sstevel@tonic-gate  * enumeration for any query. In order to avoid having to work on the
946*7c478bd9Sstevel@tonic-gate  * whole 'tab' array for simple queries (which we expect usually will
947*7c478bd9Sstevel@tonic-gate  * match just one or at most a few entries), we have a "reduced" enum mode,
948*7c478bd9Sstevel@tonic-gate  * where the caller supplies a count of the number of DB entries (derived
949*7c478bd9Sstevel@tonic-gate  * from db_mindex::satisfy_query() or similar), and then uses enumSetup()
950*7c478bd9Sstevel@tonic-gate  * to specify which 'tab' entries we're interested in.
951*7c478bd9Sstevel@tonic-gate  */
952*7c478bd9Sstevel@tonic-gate void
953*7c478bd9Sstevel@tonic-gate db_table::setEnumMode(long enumNum) {
954*7c478bd9Sstevel@tonic-gate 	char	*myself = "setEnumMode";
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	enumMode.flag++;
957*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag == 1) {
958*7c478bd9Sstevel@tonic-gate 		db_status	stat;
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 		if (enumNum < 0)
961*7c478bd9Sstevel@tonic-gate 			enumNum = 0;
962*7c478bd9Sstevel@tonic-gate 		else if (enumNum >= table_size)
963*7c478bd9Sstevel@tonic-gate 			enumNum = table_size;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 		enumCount.flag = enumNum;
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 		stat = allocateEnumArray(0, table_size);
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
970*7c478bd9Sstevel@tonic-gate 			enumMode.flag = 0;
971*7c478bd9Sstevel@tonic-gate 			enumCount.flag = 0;
972*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
973*7c478bd9Sstevel@tonic-gate 		"%s: No memory for enum check array; entry removal disabled",
974*7c478bd9Sstevel@tonic-gate 				myself);
975*7c478bd9Sstevel@tonic-gate 		}
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate }
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate void
980*7c478bd9Sstevel@tonic-gate db_table::clearEnumMode(void) {
981*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag > 0) {
982*7c478bd9Sstevel@tonic-gate 		enumMode.flag--;
983*7c478bd9Sstevel@tonic-gate 		if (enumMode.flag == 0) {
984*7c478bd9Sstevel@tonic-gate 			sfree(enumArray.ptr);
985*7c478bd9Sstevel@tonic-gate 			enumArray.ptr = 0;
986*7c478bd9Sstevel@tonic-gate 			if (enumCount.flag > 0) {
987*7c478bd9Sstevel@tonic-gate 				sfree(enumIndex.ptr);
988*7c478bd9Sstevel@tonic-gate 				enumIndex.ptr = 0;
989*7c478bd9Sstevel@tonic-gate 				enumCount.flag = 0;
990*7c478bd9Sstevel@tonic-gate 			}
991*7c478bd9Sstevel@tonic-gate 		}
992*7c478bd9Sstevel@tonic-gate 	}
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate entry_object **
996*7c478bd9Sstevel@tonic-gate db_table::endEnumMode(long *numEa) {
997*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag > 0) {
998*7c478bd9Sstevel@tonic-gate 		enumMode.flag--;
999*7c478bd9Sstevel@tonic-gate 		if (enumMode.flag == 0) {
1000*7c478bd9Sstevel@tonic-gate 			entry_obj	**ea = (entry_object **)enumArray.ptr;
1001*7c478bd9Sstevel@tonic-gate 			long		nea;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 			enumArray.ptr = 0;
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 			if (enumCount.flag > 0) {
1006*7c478bd9Sstevel@tonic-gate 				nea = enumCount.flag;
1007*7c478bd9Sstevel@tonic-gate 				enumCount.flag = 0;
1008*7c478bd9Sstevel@tonic-gate 				sfree(enumIndex.ptr);
1009*7c478bd9Sstevel@tonic-gate 				enumIndex.ptr = 0;
1010*7c478bd9Sstevel@tonic-gate 			} else {
1011*7c478bd9Sstevel@tonic-gate 				nea = table_size;
1012*7c478bd9Sstevel@tonic-gate 			}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 			if (numEa != 0)
1015*7c478bd9Sstevel@tonic-gate 				*numEa = nea;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 			return (ea);
1018*7c478bd9Sstevel@tonic-gate 		}
1019*7c478bd9Sstevel@tonic-gate 	}
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	if (numEa != 0)
1022*7c478bd9Sstevel@tonic-gate 		*numEa = 0;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	return (0);
1025*7c478bd9Sstevel@tonic-gate }
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate /*
1028*7c478bd9Sstevel@tonic-gate  * Set the appropriate entry in the enum array to NULL.
1029*7c478bd9Sstevel@tonic-gate  */
1030*7c478bd9Sstevel@tonic-gate void
1031*7c478bd9Sstevel@tonic-gate db_table::enumTouch(entryp loc) {
1032*7c478bd9Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size)
1033*7c478bd9Sstevel@tonic-gate 		return;
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag > 0) {
1036*7c478bd9Sstevel@tonic-gate 		if (enumCount.flag < 1) {
1037*7c478bd9Sstevel@tonic-gate 			((entry_object **)enumArray.ptr)[loc] = 0;
1038*7c478bd9Sstevel@tonic-gate 		} else {
1039*7c478bd9Sstevel@tonic-gate 			int	i;
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < enumCount.flag; i++) {
1042*7c478bd9Sstevel@tonic-gate 				if (loc == ((entryp *)enumIndex.ptr)[i]) {
1043*7c478bd9Sstevel@tonic-gate 					((entry_object **)enumArray.ptr)[i] = 0;
1044*7c478bd9Sstevel@tonic-gate 					break;
1045*7c478bd9Sstevel@tonic-gate 				}
1046*7c478bd9Sstevel@tonic-gate 			}
1047*7c478bd9Sstevel@tonic-gate 		}
1048*7c478bd9Sstevel@tonic-gate 	}
1049*7c478bd9Sstevel@tonic-gate }
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate /*
1052*7c478bd9Sstevel@tonic-gate  * Add the entry indicated by 'loc' to the enumIndex array, at 'index'.
1053*7c478bd9Sstevel@tonic-gate  */
1054*7c478bd9Sstevel@tonic-gate void
1055*7c478bd9Sstevel@tonic-gate db_table::enumSetup(entryp loc, long index) {
1056*7c478bd9Sstevel@tonic-gate 	if (enumMode.flag == 0 || loc < 0 || loc >= table_size ||
1057*7c478bd9Sstevel@tonic-gate 			index < 0 || index >= enumCount.flag)
1058*7c478bd9Sstevel@tonic-gate 		return;
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	((entryp *)enumIndex.ptr)[index] = loc;
1061*7c478bd9Sstevel@tonic-gate 	((entry_object **)enumArray.ptr)[index] = tab[loc];
1062*7c478bd9Sstevel@tonic-gate }
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate /*
1065*7c478bd9Sstevel@tonic-gate  * Touch, i.e., update the expiration time for the entry. Also, if enum
1066*7c478bd9Sstevel@tonic-gate  * mode is in effect, mark the entry used for enum purposes.
1067*7c478bd9Sstevel@tonic-gate  */
1068*7c478bd9Sstevel@tonic-gate void
1069*7c478bd9Sstevel@tonic-gate db_table::touchEntry(entryp loc) {
1070*7c478bd9Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
1071*7c478bd9Sstevel@tonic-gate 		return;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	setEntryExp(loc, tab[loc], 0);
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	enumTouch(loc);
1076*7c478bd9Sstevel@tonic-gate }
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate /* ************************* pickle_table ********************* */
1079*7c478bd9Sstevel@tonic-gate /* Does the actual writing to/from file specific for db_table structure. */
1080*7c478bd9Sstevel@tonic-gate /*
1081*7c478bd9Sstevel@tonic-gate  * This was a static earlier with the func name being transfer_aux. The
1082*7c478bd9Sstevel@tonic-gate  * backup and restore project needed this to copy files over.
1083*7c478bd9Sstevel@tonic-gate  */
1084*7c478bd9Sstevel@tonic-gate bool_t
1085*7c478bd9Sstevel@tonic-gate transfer_aux_table(XDR* x, pptr dp)
1086*7c478bd9Sstevel@tonic-gate {
1087*7c478bd9Sstevel@tonic-gate 	return (xdr_db_table(x, (db_table*) dp));
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate class pickle_table: public pickle_file {
1091*7c478bd9Sstevel@tonic-gate     public:
1092*7c478bd9Sstevel@tonic-gate 	pickle_table(char *f, pickle_mode m) : pickle_file(f, m) {}
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	/* Transfers db_table structure pointed to by dp to/from file. */
1095*7c478bd9Sstevel@tonic-gate 	int transfer(db_table* dp)
1096*7c478bd9Sstevel@tonic-gate 	{ return (pickle_file::transfer((pptr) dp, &transfer_aux_table)); }
1097*7c478bd9Sstevel@tonic-gate };
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate /*
1100*7c478bd9Sstevel@tonic-gate  * Writes the contents of table, including the all the entries, into the
1101*7c478bd9Sstevel@tonic-gate  * specified file in XDR format.  May need to change this to use APPEND
1102*7c478bd9Sstevel@tonic-gate  * mode instead.
1103*7c478bd9Sstevel@tonic-gate  */
1104*7c478bd9Sstevel@tonic-gate int
1105*7c478bd9Sstevel@tonic-gate db_table::dump(char *file)
1106*7c478bd9Sstevel@tonic-gate {
1107*7c478bd9Sstevel@tonic-gate 	int	ret;
1108*7c478bd9Sstevel@tonic-gate 	READLOCK(this, -1, "r db_table::dump");
1109*7c478bd9Sstevel@tonic-gate 	pickle_table f(file, PICKLE_WRITE);   /* may need to use APPEND mode */
1110*7c478bd9Sstevel@tonic-gate 	int status = f.transfer(this);
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	if (status == 1)
1113*7c478bd9Sstevel@tonic-gate 		ret = -1;
1114*7c478bd9Sstevel@tonic-gate 	else
1115*7c478bd9Sstevel@tonic-gate 		ret = status;
1116*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_table::dump");
1117*7c478bd9Sstevel@tonic-gate }
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate /* Constructor that loads in the table from the given file */
1120*7c478bd9Sstevel@tonic-gate db_table::db_table(char *file)  : freelist()
1121*7c478bd9Sstevel@tonic-gate {
1122*7c478bd9Sstevel@tonic-gate 	pickle_table f(file, PICKLE_READ);
1123*7c478bd9Sstevel@tonic-gate 	tab = NULL;
1124*7c478bd9Sstevel@tonic-gate 	table_size = last_used = count = 0;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	/* load  table */
1127*7c478bd9Sstevel@tonic-gate 	if (f.transfer(this) < 0) {
1128*7c478bd9Sstevel@tonic-gate 		/* fell through, something went wrong, initialize to null */
1129*7c478bd9Sstevel@tonic-gate 		tab = NULL;
1130*7c478bd9Sstevel@tonic-gate 		table_size = last_used = count = 0;
1131*7c478bd9Sstevel@tonic-gate 		freelist.init();
1132*7c478bd9Sstevel@tonic-gate 	}
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	db_table_ldap_init();
1135*7c478bd9Sstevel@tonic-gate 	initMappingStruct(&mapping);
1136*7c478bd9Sstevel@tonic-gate }
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate /* Returns whether location is valid. */
1139*7c478bd9Sstevel@tonic-gate bool_t db_table::entry_exists_p(entryp i) {
1140*7c478bd9Sstevel@tonic-gate 	bool_t	ret = FALSE;
1141*7c478bd9Sstevel@tonic-gate 	READLOCK(this, FALSE, "r db_table::entry_exists_p");
1142*7c478bd9Sstevel@tonic-gate 	if (tab != NULL && i < table_size)
1143*7c478bd9Sstevel@tonic-gate 		ret = tab[i] != NULL;
1144*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_table::entry_exists_p");
1145*7c478bd9Sstevel@tonic-gate 	return (ret);
1146*7c478bd9Sstevel@tonic-gate }
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate /* Empty free list */
1149*7c478bd9Sstevel@tonic-gate void db_free_list::init() {
1150*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::init");
1151*7c478bd9Sstevel@tonic-gate 	head = NULL;
1152*7c478bd9Sstevel@tonic-gate 	count = 0;
1153*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_free_list::init");
1154*7c478bd9Sstevel@tonic-gate }
1155