xref: /illumos-gate/usr/src/cmd/nscd/nscd_dbimpl.c (revision cb5caa98562cf06753163f558cbcfe30b8f4673a)
1*cb5caa98Sdjl /*
2*cb5caa98Sdjl  * CDDL HEADER START
3*cb5caa98Sdjl  *
4*cb5caa98Sdjl  * The contents of this file are subject to the terms of the
5*cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6*cb5caa98Sdjl  * You may not use this file except in compliance with the License.
7*cb5caa98Sdjl  *
8*cb5caa98Sdjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*cb5caa98Sdjl  * or http://www.opensolaris.org/os/licensing.
10*cb5caa98Sdjl  * See the License for the specific language governing permissions
11*cb5caa98Sdjl  * and limitations under the License.
12*cb5caa98Sdjl  *
13*cb5caa98Sdjl  * When distributing Covered Code, include this CDDL HEADER in each
14*cb5caa98Sdjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*cb5caa98Sdjl  * If applicable, add the following below this CDDL HEADER, with the
16*cb5caa98Sdjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*cb5caa98Sdjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*cb5caa98Sdjl  *
19*cb5caa98Sdjl  * CDDL HEADER END
20*cb5caa98Sdjl  */
21*cb5caa98Sdjl /*
22*cb5caa98Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*cb5caa98Sdjl  * Use is subject to license terms.
24*cb5caa98Sdjl  */
25*cb5caa98Sdjl 
26*cb5caa98Sdjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*cb5caa98Sdjl 
28*cb5caa98Sdjl #include <stdio.h>
29*cb5caa98Sdjl #include <stdlib.h>
30*cb5caa98Sdjl #include <string.h>
31*cb5caa98Sdjl #include <ctype.h>
32*cb5caa98Sdjl #include "nscd_db.h"
33*cb5caa98Sdjl 
34*cb5caa98Sdjl /*
35*cb5caa98Sdjl  * This file implements the database functionality used by the
36*cb5caa98Sdjl  * switch and configuration components. The implementation is
37*cb5caa98Sdjl  * based on hash and has table. If the need arises in the future,
38*cb5caa98Sdjl  * the code in this file can be changed to use other algorithms.
39*cb5caa98Sdjl  * The following lists the functions implemented:
40*cb5caa98Sdjl  *
41*cb5caa98Sdjl  * _nscd_add_db_entry
42*cb5caa98Sdjl  * _nscd_delete_db_entry
43*cb5caa98Sdjl  * _nscd_get_db_entry
44*cb5caa98Sdjl  * _nscd_alloc_db
45*cb5caa98Sdjl  * _nscd_free_db
46*cb5caa98Sdjl  * _nscd_walk_db
47*cb5caa98Sdjl  * _nscd_delete_db_entry_cookie
48*cb5caa98Sdjl  */
49*cb5caa98Sdjl 
50*cb5caa98Sdjl /*
51*cb5caa98Sdjl  * This structure defines an instance of the hash entry
52*cb5caa98Sdjl  * which implements the nscd database entry. The
53*cb5caa98Sdjl  * db_entry field should always be the first one in
54*cb5caa98Sdjl  * the structure.
55*cb5caa98Sdjl  */
56*cb5caa98Sdjl typedef struct nscd_hash {
57*cb5caa98Sdjl 	nscd_db_entry_t		db_entry;
58*cb5caa98Sdjl 	struct nscd_hash	*next_p;
59*cb5caa98Sdjl 	struct nscd_hash	*prev_p;
60*cb5caa98Sdjl } nscd_hash_t;
61*cb5caa98Sdjl 
62*cb5caa98Sdjl /*
63*cb5caa98Sdjl  * This structure defines a nscd database which
64*cb5caa98Sdjl  * is implemented as an array of nscd_hash_t.
65*cb5caa98Sdjl  */
66*cb5caa98Sdjl struct nscd_db_s {
67*cb5caa98Sdjl 	int		array_size; /* number of elements in hash_tbl_p */
68*cb5caa98Sdjl 	nscd_hash_t	**hash_tbl_p;
69*cb5caa98Sdjl };
70*cb5caa98Sdjl 
71*cb5caa98Sdjl /*
72*cb5caa98Sdjl  * This cookie structure is used to iterate through the
73*cb5caa98Sdjl  * database entries contained in a nscd database.
74*cb5caa98Sdjl  */
75*cb5caa98Sdjl struct cookie {
76*cb5caa98Sdjl 	int		idx;	/* the current bucket */
77*cb5caa98Sdjl 	nscd_hash_t	*hash;	/* the current hash entry */
78*cb5caa98Sdjl 	nscd_db_t	*db;    /* the database */
79*cb5caa98Sdjl };
80*cb5caa98Sdjl 
81*cb5caa98Sdjl /*
82*cb5caa98Sdjl  * FUNCTION: calc_hash
83*cb5caa98Sdjl  *
84*cb5caa98Sdjl  * Calculate a hash for a string based on the elf_hash
85*cb5caa98Sdjl  * algorithm, hash is case insensitive. Uses tolower
86*cb5caa98Sdjl  * instead of _tolower because of I18N.
87*cb5caa98Sdjl  */
88*cb5caa98Sdjl static unsigned long
89*cb5caa98Sdjl calc_hash(
90*cb5caa98Sdjl 	const char	*str)
91*cb5caa98Sdjl {
92*cb5caa98Sdjl 	unsigned int	hval = 0;
93*cb5caa98Sdjl 	char		ch;
94*cb5caa98Sdjl 
95*cb5caa98Sdjl 	while (*str != NULL) {
96*cb5caa98Sdjl 		unsigned int	g;
97*cb5caa98Sdjl 
98*cb5caa98Sdjl 		ch = (char)*str++;
99*cb5caa98Sdjl 		if (isupper(ch))
100*cb5caa98Sdjl 			ch = _tolower(ch);
101*cb5caa98Sdjl 		hval = (hval << 4) + ch;
102*cb5caa98Sdjl 		if ((g = (hval & 0xf0000000)) != 0)
103*cb5caa98Sdjl 			hval ^= g >> 24;
104*cb5caa98Sdjl 		hval &= ~g;
105*cb5caa98Sdjl 	}
106*cb5caa98Sdjl 	return ((unsigned long)hval);
107*cb5caa98Sdjl }
108*cb5caa98Sdjl 
109*cb5caa98Sdjl /*
110*cb5caa98Sdjl  * FUNCTION: scan_hash
111*cb5caa98Sdjl  *
112*cb5caa98Sdjl  * Scan a hash table for a matching hash entry. Assume 'str' is
113*cb5caa98Sdjl  * not NULL. If option is NSCD_GET_NEXT_DB_ENTRY and id_num
114*cb5caa98Sdjl  * is less than zero, then treats the option as NSCD_GET_FIRST_DB_ENTRY.
115*cb5caa98Sdjl  */
116*cb5caa98Sdjl 
117*cb5caa98Sdjl static const nscd_hash_t *
118*cb5caa98Sdjl scan_hash(
119*cb5caa98Sdjl 	int			type,
120*cb5caa98Sdjl 	const char		*str,
121*cb5caa98Sdjl 	const nscd_hash_t	*idx_p,
122*cb5caa98Sdjl 	nscd_db_option_t	option,
123*cb5caa98Sdjl 	int			id_num)
124*cb5caa98Sdjl {
125*cb5caa98Sdjl 	int			id_matched = 0;
126*cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
127*cb5caa98Sdjl 
128*cb5caa98Sdjl 	while (idx_p != NULL) {
129*cb5caa98Sdjl 		db_entry = &((nscd_hash_t *)idx_p)->db_entry;
130*cb5caa98Sdjl 		if (db_entry->type == type) {
131*cb5caa98Sdjl 			if (strcasecmp(str, db_entry->name) == 0) {
132*cb5caa98Sdjl 				switch (option) {
133*cb5caa98Sdjl 				case NSCD_GET_FIRST_DB_ENTRY:
134*cb5caa98Sdjl 					return (idx_p);
135*cb5caa98Sdjl 				case NSCD_GET_EXACT_DB_ENTRY:
136*cb5caa98Sdjl 					if (id_num == db_entry->id_num)
137*cb5caa98Sdjl 						return (idx_p);
138*cb5caa98Sdjl 					break;
139*cb5caa98Sdjl 				case NSCD_GET_NEXT_DB_ENTRY:
140*cb5caa98Sdjl 					if (id_num < 0)
141*cb5caa98Sdjl 						return (idx_p);
142*cb5caa98Sdjl 					if (id_matched == 1)
143*cb5caa98Sdjl 						return (idx_p);
144*cb5caa98Sdjl 					if (id_num == db_entry->id_num)
145*cb5caa98Sdjl 						id_matched = 1;
146*cb5caa98Sdjl 					break;
147*cb5caa98Sdjl 				}
148*cb5caa98Sdjl 			}
149*cb5caa98Sdjl 		}
150*cb5caa98Sdjl 		idx_p = idx_p->next_p;
151*cb5caa98Sdjl 	}
152*cb5caa98Sdjl 	return (NULL);
153*cb5caa98Sdjl }
154*cb5caa98Sdjl 
155*cb5caa98Sdjl /*
156*cb5caa98Sdjl  * FUNCTION: _nscd_get_db_entry
157*cb5caa98Sdjl  *
158*cb5caa98Sdjl  * Find a nscd database entry from a nscd database.
159*cb5caa98Sdjl  */
160*cb5caa98Sdjl const nscd_db_entry_t *
161*cb5caa98Sdjl _nscd_get_db_entry(
162*cb5caa98Sdjl 	const nscd_db_t		*db,
163*cb5caa98Sdjl 	int			type,
164*cb5caa98Sdjl 	const char		*str,
165*cb5caa98Sdjl 	nscd_db_option_t	option,
166*cb5caa98Sdjl 	int			id_num)
167*cb5caa98Sdjl {
168*cb5caa98Sdjl 	unsigned long		hash;
169*cb5caa98Sdjl 	const nscd_hash_t	*idx_p, *hash_p;
170*cb5caa98Sdjl 
171*cb5caa98Sdjl 	if (db == NULL || str == NULL)
172*cb5caa98Sdjl 		return (NULL);
173*cb5caa98Sdjl 
174*cb5caa98Sdjl 	hash = calc_hash(str);
175*cb5caa98Sdjl 	idx_p = db->hash_tbl_p[hash % db->array_size];
176*cb5caa98Sdjl 
177*cb5caa98Sdjl 	hash_p = scan_hash(type, str, idx_p, option, id_num);
178*cb5caa98Sdjl 
179*cb5caa98Sdjl 	return (&hash_p->db_entry);
180*cb5caa98Sdjl }
181*cb5caa98Sdjl 
182*cb5caa98Sdjl /*
183*cb5caa98Sdjl  * FUNCTION: _nscd_add_db_entry
184*cb5caa98Sdjl  *
185*cb5caa98Sdjl  * Add a nscd database entry to a nscd database. This function
186*cb5caa98Sdjl  * is not MT safe. The caller should lock the database to
187*cb5caa98Sdjl  * prevent concurrent updates done by other threads.
188*cb5caa98Sdjl  */
189*cb5caa98Sdjl nscd_rc_t
190*cb5caa98Sdjl _nscd_add_db_entry(
191*cb5caa98Sdjl 	nscd_db_t		*db,
192*cb5caa98Sdjl 	const char 		*str,
193*cb5caa98Sdjl 	nscd_db_entry_t		*entry,
194*cb5caa98Sdjl 	nscd_db_option_t	option)
195*cb5caa98Sdjl {
196*cb5caa98Sdjl 	int			i;
197*cb5caa98Sdjl 	unsigned long		hash;
198*cb5caa98Sdjl 	nscd_hash_t		*next_p = NULL, *prev_p = NULL;
199*cb5caa98Sdjl 	nscd_hash_t		*idx_p, *hash_entry;
200*cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
201*cb5caa98Sdjl 
202*cb5caa98Sdjl 	/* find the bucket */
203*cb5caa98Sdjl 	hash = calc_hash(str);
204*cb5caa98Sdjl 	i = hash % db->array_size;
205*cb5caa98Sdjl 	idx_p = db->hash_tbl_p[i];
206*cb5caa98Sdjl 
207*cb5caa98Sdjl 	/* can not replace nothing */
208*cb5caa98Sdjl 	if (idx_p == NULL)
209*cb5caa98Sdjl 		if (option == NSCD_ADD_DB_ENTRY_REPLACE)
210*cb5caa98Sdjl 			return (NSCD_DB_ENTRY_NOT_FOUND);
211*cb5caa98Sdjl 
212*cb5caa98Sdjl 	while (idx_p != NULL) {
213*cb5caa98Sdjl 		db_entry = &idx_p->db_entry;
214*cb5caa98Sdjl 		switch (option) {
215*cb5caa98Sdjl 
216*cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_FIRST:
217*cb5caa98Sdjl 			next_p = idx_p;
218*cb5caa98Sdjl 			goto add_entry;
219*cb5caa98Sdjl 
220*cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_REPLACE:
221*cb5caa98Sdjl 			if (db_entry->type != entry->type)
222*cb5caa98Sdjl 				goto cont;
223*cb5caa98Sdjl 			if (strcasecmp(db_entry->name, str) != 0)
224*cb5caa98Sdjl 				goto cont;
225*cb5caa98Sdjl 
226*cb5caa98Sdjl 			if (db_entry->id_num == entry->id_num) {
227*cb5caa98Sdjl 				prev_p = idx_p->prev_p;
228*cb5caa98Sdjl 				next_p = idx_p->next_p;
229*cb5caa98Sdjl 				free(idx_p);
230*cb5caa98Sdjl 				goto add_entry;
231*cb5caa98Sdjl 			}
232*cb5caa98Sdjl 			goto cont;
233*cb5caa98Sdjl 
234*cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_IF_NONE:
235*cb5caa98Sdjl 			if (db_entry->type != entry->type)
236*cb5caa98Sdjl 				break;
237*cb5caa98Sdjl 			if (strcasecmp(db_entry->name, str) != 0)
238*cb5caa98Sdjl 				break;
239*cb5caa98Sdjl 			return (NSCD_DB_ENTRY_FOUND);
240*cb5caa98Sdjl 		}
241*cb5caa98Sdjl 
242*cb5caa98Sdjl 		if (idx_p->next_p == NULL) {
243*cb5caa98Sdjl 			if (option == NSCD_ADD_DB_ENTRY_LAST ||
244*cb5caa98Sdjl 				option == NSCD_ADD_DB_ENTRY_IF_NONE) {
245*cb5caa98Sdjl 				prev_p = idx_p;
246*cb5caa98Sdjl 				goto add_entry;
247*cb5caa98Sdjl 			}
248*cb5caa98Sdjl 		}
249*cb5caa98Sdjl 
250*cb5caa98Sdjl 		cont:
251*cb5caa98Sdjl 		idx_p = idx_p->next_p;
252*cb5caa98Sdjl 	}
253*cb5caa98Sdjl 
254*cb5caa98Sdjl 	add_entry:
255*cb5caa98Sdjl 
256*cb5caa98Sdjl 	/*
257*cb5caa98Sdjl 	 * the nscd_entry_t field should be the first field
258*cb5caa98Sdjl 	 * in a nscd_hash_t
259*cb5caa98Sdjl 	 */
260*cb5caa98Sdjl 	hash_entry = (nscd_hash_t *)entry;
261*cb5caa98Sdjl 
262*cb5caa98Sdjl 	/* update the prev link list */
263*cb5caa98Sdjl 	hash_entry->prev_p = prev_p;
264*cb5caa98Sdjl 	if (prev_p == NULL)
265*cb5caa98Sdjl 		db->hash_tbl_p[i] = hash_entry;
266*cb5caa98Sdjl 	else
267*cb5caa98Sdjl 		prev_p->next_p = hash_entry;
268*cb5caa98Sdjl 
269*cb5caa98Sdjl 	/* update the next link list */
270*cb5caa98Sdjl 	hash_entry->next_p = next_p;
271*cb5caa98Sdjl 	if (next_p != NULL)
272*cb5caa98Sdjl 		next_p->prev_p = hash_entry;
273*cb5caa98Sdjl 
274*cb5caa98Sdjl 	return (NSCD_SUCCESS);
275*cb5caa98Sdjl }
276*cb5caa98Sdjl 
277*cb5caa98Sdjl /*
278*cb5caa98Sdjl  * FUNCTION: _nscd_delete_db_entry
279*cb5caa98Sdjl  *
280*cb5caa98Sdjl  * Delete a nscd database entry from a nscd database. This
281*cb5caa98Sdjl  * function is not MT safe. The caller should lock the
282*cb5caa98Sdjl  * database to prevent concurrent updates done by other
283*cb5caa98Sdjl  * threads.
284*cb5caa98Sdjl  */
285*cb5caa98Sdjl nscd_rc_t
286*cb5caa98Sdjl _nscd_delete_db_entry(
287*cb5caa98Sdjl 	nscd_db_t		*db,
288*cb5caa98Sdjl 	int			type,
289*cb5caa98Sdjl 	const char		*str,
290*cb5caa98Sdjl 	nscd_db_option_t	option,
291*cb5caa98Sdjl 	int			id_num)
292*cb5caa98Sdjl {
293*cb5caa98Sdjl 	int			i;
294*cb5caa98Sdjl 	int			del_more = 0;
295*cb5caa98Sdjl 	unsigned long		hash;
296*cb5caa98Sdjl 	nscd_hash_t		*idx_p, *next_p = NULL, *prev_p = NULL;
297*cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
298*cb5caa98Sdjl 
299*cb5caa98Sdjl 	/* find the bucket */
300*cb5caa98Sdjl 	hash = calc_hash(str);
301*cb5caa98Sdjl 	i = hash % db->array_size;
302*cb5caa98Sdjl 	idx_p = db->hash_tbl_p[i];
303*cb5caa98Sdjl 
304*cb5caa98Sdjl 	/* delete nothing always works */
305*cb5caa98Sdjl 	if (idx_p == NULL)
306*cb5caa98Sdjl 		return (NSCD_SUCCESS);
307*cb5caa98Sdjl 
308*cb5caa98Sdjl 	while (idx_p != NULL) {
309*cb5caa98Sdjl 		db_entry = &idx_p->db_entry;
310*cb5caa98Sdjl 		if (db_entry->type != type)
311*cb5caa98Sdjl 			goto cont;
312*cb5caa98Sdjl 		if (strcasecmp(db_entry->name, str) != 0)
313*cb5caa98Sdjl 			goto cont;
314*cb5caa98Sdjl 
315*cb5caa98Sdjl 		switch (option) {
316*cb5caa98Sdjl 
317*cb5caa98Sdjl 		case NSCD_DEL_FIRST_DB_ENTRY:
318*cb5caa98Sdjl 			prev_p = idx_p->prev_p;
319*cb5caa98Sdjl 			next_p = idx_p->next_p;
320*cb5caa98Sdjl 			del_more = 0;
321*cb5caa98Sdjl 			break;
322*cb5caa98Sdjl 
323*cb5caa98Sdjl 		case NSCD_DEL_EXACT_DB_ENTRY:
324*cb5caa98Sdjl 			if (db_entry->id_num == id_num) {
325*cb5caa98Sdjl 				prev_p = idx_p->prev_p;
326*cb5caa98Sdjl 				next_p = idx_p->next_p;
327*cb5caa98Sdjl 				del_more = 0;
328*cb5caa98Sdjl 			} else
329*cb5caa98Sdjl 				goto cont;
330*cb5caa98Sdjl 			break;
331*cb5caa98Sdjl 
332*cb5caa98Sdjl 		case NSCD_DEL_ALL_DB_ENTRY:
333*cb5caa98Sdjl 			prev_p = idx_p->prev_p;
334*cb5caa98Sdjl 			next_p = idx_p->next_p;
335*cb5caa98Sdjl 			break;
336*cb5caa98Sdjl 		}
337*cb5caa98Sdjl 
338*cb5caa98Sdjl 		if (prev_p == NULL)
339*cb5caa98Sdjl 			db->hash_tbl_p[i] = next_p;
340*cb5caa98Sdjl 		else
341*cb5caa98Sdjl 			prev_p->next_p = next_p;
342*cb5caa98Sdjl 
343*cb5caa98Sdjl 		if (next_p != NULL)
344*cb5caa98Sdjl 			next_p->prev_p = prev_p;
345*cb5caa98Sdjl 
346*cb5caa98Sdjl 		free(idx_p);
347*cb5caa98Sdjl 
348*cb5caa98Sdjl 		if (del_more == 0)
349*cb5caa98Sdjl 			break;
350*cb5caa98Sdjl 		/*
351*cb5caa98Sdjl 		 * only when option == NSCD_DEL_ALL_DB_ENTRY
352*cb5caa98Sdjl 		 * will we get here. next_p should be set to
353*cb5caa98Sdjl 		 * idx_p->next_p beforehand
354*cb5caa98Sdjl 		 */
355*cb5caa98Sdjl 		idx_p = next_p;
356*cb5caa98Sdjl 		continue;
357*cb5caa98Sdjl 
358*cb5caa98Sdjl 		cont:
359*cb5caa98Sdjl 
360*cb5caa98Sdjl 		idx_p = idx_p->next_p;
361*cb5caa98Sdjl 	}
362*cb5caa98Sdjl 
363*cb5caa98Sdjl 	return (NSCD_SUCCESS);
364*cb5caa98Sdjl }
365*cb5caa98Sdjl 
366*cb5caa98Sdjl /*
367*cb5caa98Sdjl  * FUNCTION: _nscd_alloc_db_entry
368*cb5caa98Sdjl  *
369*cb5caa98Sdjl  * Allocate and return the memory for a database entry
370*cb5caa98Sdjl  * so the caller can insert data and then add it to the
371*cb5caa98Sdjl  * database.
372*cb5caa98Sdjl  */
373*cb5caa98Sdjl nscd_db_entry_t *
374*cb5caa98Sdjl _nscd_alloc_db_entry(
375*cb5caa98Sdjl 	int			type,
376*cb5caa98Sdjl 	const char 		*name,
377*cb5caa98Sdjl 	int			dataSize,
378*cb5caa98Sdjl 	int			num_data,
379*cb5caa98Sdjl 	int			num_array)
380*cb5caa98Sdjl {
381*cb5caa98Sdjl 	int			size;
382*cb5caa98Sdjl 	int			array_o, data_o;
383*cb5caa98Sdjl 	nscd_hash_t		*hash;
384*cb5caa98Sdjl 	void			*p;
385*cb5caa98Sdjl 
386*cb5caa98Sdjl 	/* first part: hash data structure and name string */
387*cb5caa98Sdjl 	size = sizeof (*hash) + strlen(name) + 1;
388*cb5caa98Sdjl 	array_o = size = roundup(size);
389*cb5caa98Sdjl 
390*cb5caa98Sdjl 	/* second part: pointer array to data */
391*cb5caa98Sdjl 	size += (num_data  + num_array) * sizeof (void **);
392*cb5caa98Sdjl 	size = roundup(size);
393*cb5caa98Sdjl 
394*cb5caa98Sdjl 	/* third part: actual data */
395*cb5caa98Sdjl 	data_o = size;
396*cb5caa98Sdjl 	size += dataSize;
397*cb5caa98Sdjl 
398*cb5caa98Sdjl 	/* allocate the memory */
399*cb5caa98Sdjl 	hash = (nscd_hash_t *)calloc(1, size);
400*cb5caa98Sdjl 
401*cb5caa98Sdjl 	if (hash == NULL)
402*cb5caa98Sdjl 		return (NULL);
403*cb5caa98Sdjl 
404*cb5caa98Sdjl 	/* init the entry based on caller's input */
405*cb5caa98Sdjl 	hash->db_entry.num_data = num_data;
406*cb5caa98Sdjl 	hash->db_entry.num_array = num_array;
407*cb5caa98Sdjl 	hash->db_entry.type = type;
408*cb5caa98Sdjl 	hash->db_entry.name = (char *)hash + sizeof (*hash);
409*cb5caa98Sdjl 	p = (char *)hash + array_o;
410*cb5caa98Sdjl 	hash->db_entry.data_array = (void **)p;
411*cb5caa98Sdjl 	*(hash->db_entry.data_array) = (char *)hash + data_o;
412*cb5caa98Sdjl 	(void) strcpy(hash->db_entry.name, name);
413*cb5caa98Sdjl 
414*cb5caa98Sdjl 	return (&hash->db_entry);
415*cb5caa98Sdjl }
416*cb5caa98Sdjl 
417*cb5caa98Sdjl /*
418*cb5caa98Sdjl  * FUNCTION: _nscd_delete_db_entry_cookie
419*cb5caa98Sdjl  *
420*cb5caa98Sdjl  * Delete a database entry using the information from
421*cb5caa98Sdjl  * the input 'cookie'.
422*cb5caa98Sdjl  */
423*cb5caa98Sdjl void
424*cb5caa98Sdjl _nscd_delete_db_entry_cookie(
425*cb5caa98Sdjl 	nscd_db_t	*db,
426*cb5caa98Sdjl 	void		**cookie)
427*cb5caa98Sdjl {
428*cb5caa98Sdjl 	nscd_hash_t	*hp;
429*cb5caa98Sdjl 	struct cookie	*c;
430*cb5caa98Sdjl 
431*cb5caa98Sdjl 	/* snaity check */
432*cb5caa98Sdjl 	if (cookie == NULL || *cookie == NULL || db == NULL)
433*cb5caa98Sdjl 		return;
434*cb5caa98Sdjl 	c = *cookie;
435*cb5caa98Sdjl 
436*cb5caa98Sdjl 	/* more snaity check */
437*cb5caa98Sdjl 	if (db != c->db || c->hash == NULL ||
438*cb5caa98Sdjl 		c->idx < 0 || c->idx >= db->array_size)
439*cb5caa98Sdjl 		return;
440*cb5caa98Sdjl 
441*cb5caa98Sdjl 	/* retrieve the hash entry from the cookie */
442*cb5caa98Sdjl 	hp = c->hash;
443*cb5caa98Sdjl 
444*cb5caa98Sdjl 	/*
445*cb5caa98Sdjl 	 * Update the next/previous link list.
446*cb5caa98Sdjl 	 * Need to update c->hash as well, in case
447*cb5caa98Sdjl 	 * the cookie is also used in a walk-db
448*cb5caa98Sdjl 	 * loop. This is to make sure that the
449*cb5caa98Sdjl 	 * next _nscd_walk_db() call will
450*cb5caa98Sdjl 	 * find the (updated) next hash entry in line.
451*cb5caa98Sdjl 	 */
452*cb5caa98Sdjl 	if (hp->prev_p == NULL)	{
453*cb5caa98Sdjl 		/*
454*cb5caa98Sdjl 		 * make sure the current bucket will be
455*cb5caa98Sdjl 		 * walked again if _nscd_walk_db is
456*cb5caa98Sdjl 		 * called next
457*cb5caa98Sdjl 		 */
458*cb5caa98Sdjl 		c->hash = NULL;
459*cb5caa98Sdjl 		db->hash_tbl_p[c->idx] = hp->next_p;
460*cb5caa98Sdjl 		c->idx--;
461*cb5caa98Sdjl 
462*cb5caa98Sdjl 	} else {
463*cb5caa98Sdjl 		c->hash = hp->prev_p;
464*cb5caa98Sdjl 		hp->prev_p->next_p = hp->next_p;
465*cb5caa98Sdjl 	}
466*cb5caa98Sdjl 	if (hp->next_p != NULL)
467*cb5caa98Sdjl 		hp->next_p->prev_p = hp->prev_p;
468*cb5caa98Sdjl 
469*cb5caa98Sdjl 	/* delete the entry */
470*cb5caa98Sdjl 	free(hp);
471*cb5caa98Sdjl }
472*cb5caa98Sdjl 
473*cb5caa98Sdjl /*
474*cb5caa98Sdjl  * FUNCTION: _nscd_alloc_db
475*cb5caa98Sdjl  *
476*cb5caa98Sdjl  * Allocate the space for a nscd database.
477*cb5caa98Sdjl  *
478*cb5caa98Sdjl  * The input argument, size, indicates the size of the database.
479*cb5caa98Sdjl  * NSCD_DB_SIZE_LARGE specifies an bucket array of size 67,
480*cb5caa98Sdjl  * NSCD_DB_SIZE_MEDIUM specifies an bucket array of size 37,
481*cb5caa98Sdjl  * NSCD_DB_SIZE_SMALL specifies an bucket array of size 13,
482*cb5caa98Sdjl  * NSCD_DB_SIZE_TINY specifies an bucket array of size 3.
483*cb5caa98Sdjl  */
484*cb5caa98Sdjl nscd_db_t *
485*cb5caa98Sdjl _nscd_alloc_db(
486*cb5caa98Sdjl 	int		size)
487*cb5caa98Sdjl {
488*cb5caa98Sdjl 	int		sz;
489*cb5caa98Sdjl 	nscd_db_t	*db;
490*cb5caa98Sdjl 
491*cb5caa98Sdjl 	/* allocate the database */
492*cb5caa98Sdjl 	db = (nscd_db_t *)calloc(1, sizeof (nscd_db_t));
493*cb5caa98Sdjl 	if (db == NULL)
494*cb5caa98Sdjl 		return (NULL);
495*cb5caa98Sdjl 
496*cb5caa98Sdjl 	/* allocate the bucket array */
497*cb5caa98Sdjl 	if (size == NSCD_DB_SIZE_LARGE)
498*cb5caa98Sdjl 		sz = 67;
499*cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_MEDIUM)
500*cb5caa98Sdjl 		sz = 37;
501*cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_SMALL)
502*cb5caa98Sdjl 		sz = 13;
503*cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_TINY)
504*cb5caa98Sdjl 		sz = 3;
505*cb5caa98Sdjl 	db->hash_tbl_p = (nscd_hash_t  **)calloc(sz + 1,
506*cb5caa98Sdjl 			sizeof (nscd_hash_t *));
507*cb5caa98Sdjl 	if (db->hash_tbl_p == NULL) {
508*cb5caa98Sdjl 		free(db);
509*cb5caa98Sdjl 		return (NULL);
510*cb5caa98Sdjl 	}
511*cb5caa98Sdjl 
512*cb5caa98Sdjl 	db->array_size = sz;
513*cb5caa98Sdjl 
514*cb5caa98Sdjl 	return (db);
515*cb5caa98Sdjl }
516*cb5caa98Sdjl 
517*cb5caa98Sdjl /*
518*cb5caa98Sdjl  * FUNCTION: _nscd_free_db
519*cb5caa98Sdjl  *
520*cb5caa98Sdjl  * Delete a nscd database.
521*cb5caa98Sdjl  */
522*cb5caa98Sdjl void
523*cb5caa98Sdjl _nscd_free_db(
524*cb5caa98Sdjl 	nscd_db_t	*db)
525*cb5caa98Sdjl {
526*cb5caa98Sdjl 	int		i;
527*cb5caa98Sdjl 	nscd_hash_t	*hp, *next_p;
528*cb5caa98Sdjl 
529*cb5caa98Sdjl 	/*
530*cb5caa98Sdjl 	 * find non-empty buckets and for each one of them,
531*cb5caa98Sdjl 	 * delete all the database entries in it's link list
532*cb5caa98Sdjl 	 */
533*cb5caa98Sdjl 	for (i = 0; i < db->array_size; i++) {
534*cb5caa98Sdjl 
535*cb5caa98Sdjl 		hp = db->hash_tbl_p[i];
536*cb5caa98Sdjl 
537*cb5caa98Sdjl 		while (hp != NULL) {
538*cb5caa98Sdjl 			next_p = hp->next_p;
539*cb5caa98Sdjl 			free(hp);
540*cb5caa98Sdjl 			hp = next_p;
541*cb5caa98Sdjl 		}
542*cb5caa98Sdjl 	}
543*cb5caa98Sdjl 
544*cb5caa98Sdjl 	/* free the bucket array */
545*cb5caa98Sdjl 	free(db->hash_tbl_p);
546*cb5caa98Sdjl 
547*cb5caa98Sdjl 	free(db);
548*cb5caa98Sdjl }
549*cb5caa98Sdjl 
550*cb5caa98Sdjl /*
551*cb5caa98Sdjl  * FUNCTION: _nscd_walk_db
552*cb5caa98Sdjl  *
553*cb5caa98Sdjl  * Iterate through the database entries contained in
554*cb5caa98Sdjl  * a nscd database and return one entry at a time.
555*cb5caa98Sdjl  * The cookie structure is used to indicate the
556*cb5caa98Sdjl  * location of the returned entry for the next call
557*cb5caa98Sdjl  * to this function. For the very first call, *cookie
558*cb5caa98Sdjl  * should be set to NULL. For subsequent calls, the one
559*cb5caa98Sdjl  * returned by the previous call sould be used.
560*cb5caa98Sdjl  */
561*cb5caa98Sdjl nscd_db_entry_t *
562*cb5caa98Sdjl _nscd_walk_db(
563*cb5caa98Sdjl 	nscd_db_t	*db,
564*cb5caa98Sdjl 	void		**cookie)
565*cb5caa98Sdjl {
566*cb5caa98Sdjl 	struct cookie	*c;
567*cb5caa98Sdjl 
568*cb5caa98Sdjl 	/* sanity check */
569*cb5caa98Sdjl 	if (cookie == NULL || db == NULL)
570*cb5caa98Sdjl 		return (NULL);
571*cb5caa98Sdjl 
572*cb5caa98Sdjl 	if (*cookie != NULL) {
573*cb5caa98Sdjl 
574*cb5caa98Sdjl 		c = *cookie;
575*cb5caa98Sdjl 
576*cb5caa98Sdjl 		/*
577*cb5caa98Sdjl 		 * More sanity check. _nscd_delete_db_entry_cookie()
578*cb5caa98Sdjl 		 * could change c->idx to -1.
579*cb5caa98Sdjl 		 */
580*cb5caa98Sdjl 		if (db != c->db ||
581*cb5caa98Sdjl 			c->idx < -1 || c->idx >= db->array_size)
582*cb5caa98Sdjl 			return (NULL);
583*cb5caa98Sdjl 
584*cb5caa98Sdjl 		/* is there a next entry ? */
585*cb5caa98Sdjl 		if (c->hash != NULL)
586*cb5caa98Sdjl 			c->hash = c->hash->next_p;
587*cb5caa98Sdjl 
588*cb5caa98Sdjl 		/* yes, return it */
589*cb5caa98Sdjl 		if (c->hash != NULL) {
590*cb5caa98Sdjl 			return (&c->hash->db_entry);
591*cb5caa98Sdjl 		}
592*cb5caa98Sdjl 	} else {
593*cb5caa98Sdjl 		c = (struct cookie *)calloc(1, sizeof (*c));
594*cb5caa98Sdjl 		if (c == NULL)
595*cb5caa98Sdjl 			return (NULL);
596*cb5caa98Sdjl 		c->idx = -1;
597*cb5caa98Sdjl 		c->hash = NULL;
598*cb5caa98Sdjl 		c->db = db;
599*cb5caa98Sdjl 	}
600*cb5caa98Sdjl 
601*cb5caa98Sdjl 	/* find the first non-empty bucket */
602*cb5caa98Sdjl 	for (c->idx++; c->idx < db->array_size; c->idx++) {
603*cb5caa98Sdjl 		c->hash = db->hash_tbl_p[c->idx];
604*cb5caa98Sdjl 		if (c->hash != NULL)
605*cb5caa98Sdjl 			break;
606*cb5caa98Sdjl 	}
607*cb5caa98Sdjl 
608*cb5caa98Sdjl 	/* no (more) non-empty bucket, we are done */
609*cb5caa98Sdjl 	if (c->hash == NULL) {
610*cb5caa98Sdjl 		free(c);
611*cb5caa98Sdjl 		*cookie = NULL;
612*cb5caa98Sdjl 		return (NULL);
613*cb5caa98Sdjl 	}
614*cb5caa98Sdjl 
615*cb5caa98Sdjl 	*cookie = c;
616*cb5caa98Sdjl 	return (&c->hash->db_entry);
617*cb5caa98Sdjl }
618