xref: /titanic_44/usr/src/lib/libnisdb/yptol/map_ctrl.c (revision c5a865cb9dc6d04c7da5ddf9360f131a4931968a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * DESCRIPTION:	Contains functions relating to the creation and manipulation
30  *		of map_ctrl structures. These are used to hold information
31  *		specific to one NIS map.
32  *
33  *		Because each of these contains a significant amount of state
34  *		information about an individual map they are created (on the
35  *		heap) when a map is opened and destroyed when it is closed.
36  *		The overhead of doing this is less than maintaining a pool
37  *		of map_ctrls.
38  *
39  *		If two processes access the same map two map_ctrls will be
40  *		created with similar contents (but differing DBM pointers).
41  *		Both will have the same hash value so when one is locked
42  *		access to the other will also be prevented.
43  */
44 
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <syslog.h>
48 #include <ndbm.h>
49 #include <string.h>
50 #include <sys/param.h>
51 #include "ypsym.h"
52 #include "ypdefs.h"
53 #include "shim.h"
54 #include "yptol.h"
55 #include "../ldap_util.h"
56 
57 extern int hash(char *s);
58 extern bool_t add_map_domain_to_list(char *domain, char ***map_list);
59 
60 /*
61  * Static variables for locking mechanism in
62  * N2L mode.
63  *  map_id_list: hash table for map lists
64  *  max_map: max number of maps in map_id_list
65  *      it is also used as the map ID for
66  *      unknown maps, see get_map_id()
67  *      in usr/src/cmd/ypcmd/shared/lockmap.c
68  */
69 static map_id_elt_t *map_id_list[MAXHASH];
70 static int max_map = 0;
71 
72 /* Switch on parts of ypdefs.h */
73 USE_DBM
74 USE_YPDBPATH
75 
76 /*
77  * FUNCTION: 	create_map_ctrl();
78  *
79  * DESCRIPTION: Create and a new map_ctrl in a non opened state.
80  *
81  * INPUTS:	Fully qualified map name
82  *
83  * OUTPUTS:	Pointer to map_ctrl
84  *		NULL on failure.
85  *
86  */
87 map_ctrl *
create_map_ctrl(char * name)88 create_map_ctrl(char *name)
89 {
90 	char *myself = "create_map_ctrl";
91 	map_ctrl *map;
92 
93 	map = (map_ctrl *)am(myself, sizeof (map_ctrl));
94 	if (NULL == map) {
95 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not alloc map_ctrl");
96 		return (NULL);
97 	}
98 
99 	/* Clear new map (in case we have to free it) */
100 	map->entries = NULL;
101 	map->hash_val = 0;
102 	map->map_name = NULL;
103 	map->domain = NULL;
104 	map->map_path = NULL;
105 	map->ttl = NULL;
106 	map->ttl_path = NULL;
107 	map->trad_map_path = NULL;
108 	map->key_data.dptr = NULL;
109 	map->open_mode = 0;
110 	map->open_flags = 0;
111 
112 	/*
113 	 * Initialize the fields of the map_ctrl. By doing this once here we
114 	 * can save a lot of work as map entries are accessed.
115 	 */
116 	if (SUCCESS != map_ctrl_init(map, name)) {
117 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
118 				"Could not initialize map_ctrl for %s", name);
119 		free_map_ctrl(map);
120 		return (NULL);
121 	}
122 
123 	return (map);
124 }
125 
126 /*
127  * FUNCTION :	map_ctrl_init()
128  *
129  * DESCRIPTION:	Initializes the fields of a map_ctrl structure.
130  *
131  *		By doing this once (when the map_ctrl is created) we avoid
132  *		numerous other function having to repeat this string
133  *		manipulation.
134  *
135  * GIVEN :	Pointer to the structure
136  *		Fully qualified name of the map
137  *
138  * RETURNS :	SUCCESS = map_ctrl fully set up.
139  *		FAILURE = map_ctrl not set up CALLER MUST FREE.
140  */
141 suc_code
map_ctrl_init(map_ctrl * map,char * name)142 map_ctrl_init(map_ctrl *map, char *name)
143 {
144 	char *myself = "map_ctrl_init";
145 	char *p, *q;
146 
147 	/* Save map path for future reference */
148 	map->map_path = (char *)strdup(name);
149 	if (NULL ==  map->map_path) {
150 		logmsg(MSG_NOMEM, LOG_ERR,
151 				"Could not duplicate map path %s", map);
152 		return (FAILURE);
153 	}
154 
155 	/* Work out map's unqualified name from path */
156 	p = strrchr(name, SEP_CHAR);
157 	if (NULL == p) {
158 		/* Must be at least a domain and name */
159 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
160 			"Could not find separator in map path %s", map);
161 		return (FAILURE);
162 	}
163 	q = p + 1;
164 
165 	/* Check for and remove N2L prefix */
166 	if (yptol_mode) {
167 		/*
168 		 * Check for and remove N2L prefix. If not found not a problem
169 		 * we open some old style maps during DIT initialization.
170 		 */
171 		if (0 == strncmp(q, NTOL_PREFIX, strlen(NTOL_PREFIX)))
172 			q += strlen(NTOL_PREFIX);
173 	} else {
174 		if (0 == strncmp(q, NTOL_PREFIX, strlen(NTOL_PREFIX)))
175 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
176 				"Working in non N2L mode and path %s "
177 				"contains N2L prefix", name);
178 	}
179 
180 	/* Save unqualified map name */
181 	map->map_name = strdup(q);
182 	if (NULL == map->map_name) {
183 		logmsg(MSG_NOMEM, LOG_ERR,
184 				"Could not duplicate map name %s", q);
185 		return (FAILURE);
186 	}
187 
188 	/* Work out map's domain name from path */
189 	for (q = p-1; (SEP_CHAR != *q) && (q > name); q--);
190 
191 	if (q <= name) {
192 		/* Didn't find separator */
193 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
194 				"Could not find domain in map path %s", name);
195 		return (FAILURE);
196 	}
197 
198 	map->domain = (char *)am(myself, p - q);
199 	if (NULL == map->domain) {
200 		logmsg(MSG_NOMEM, LOG_ERR,
201 			"Could not alloc memory for domain in path %s", name);
202 		return (FAILURE);
203 	}
204 	(void) strncpy(map->domain, q + 1, p-q-1);
205 	map->domain[p-q-1] = '\0';
206 
207 	/* Work out extra names required by N2L */
208 	if (yptol_mode) {
209 		/*
210 		 * Work out what old style NIS path would have been. This is
211 		 * used to check for date of DBM file so add the DBM
212 		 * extension.
213 		 */
214 		map->trad_map_path = (char *)am(myself, strlen(map->map_name) +
215 					+ strlen(dbm_pag) + (p - name) + 2);
216 		if (NULL == map->trad_map_path) {
217 			logmsg(MSG_NOMEM, LOG_ERR,
218 				"Could not alocate memory for "
219 				"traditional map path derived from %s", name);
220 			return (FAILURE);
221 		}
222 
223 		strncpy(map->trad_map_path, name, p - name + 1);
224 		map->trad_map_path[p - name + 1] = '\0';
225 		strcat(map->trad_map_path, map->map_name);
226 		strcat(map->trad_map_path, dbm_pag);
227 
228 		/* Generate qualified TTL file name */
229 		map->ttl_path = (char *)am(myself, strlen(map->map_path) +
230 						strlen(TTL_POSTFIX) + 1);
231 		if (NULL == map->ttl_path) {
232 			logmsg(MSG_NOMEM, LOG_ERR,
233 				"Could not alocate memory for "
234 				"ttl path derived from %s", name);
235 			return (FAILURE);
236 		}
237 
238 		strcpy(map->ttl_path, map->map_path);
239 		strcat(map->ttl_path, TTL_POSTFIX);
240 	}
241 
242 	/* Work out hash value */
243 	map->hash_val = hash(name);
244 
245 	/* Set up magic number */
246 	map->magic = MAP_MAGIC;
247 
248 	/* Null out pointers */
249 	map->entries = NULL;
250 	map->ttl = NULL;
251 
252 	/* No key data yet */
253 	map->key_data.dptr = NULL;
254 	map->key_data.dsize = 0;
255 
256 	return (SUCCESS);
257 }
258 
259 /*
260  * FUNCTION: 	get_map_crtl();
261  *
262  * DESCRIPTION: Find an existing map_ctrl for a map of a given DBM * (i.e.
263  *		handle) . If none exists return an error.
264  *
265  * INPUTS:	Map handle
266  *
267  * OUTPUTS:	Pointer to map_ctrl
268  *		NULL on failure.
269  *
270  */
271 map_ctrl *
get_map_ctrl(DBM * db)272 get_map_ctrl(DBM *db)
273 {
274 	/* Check that this really is a map_ctrl not a DBM */
275 	if (((map_ctrl *)db)->magic != MAP_MAGIC) {
276 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
277 				"SHIM called with DBM ptr not map_crtl ptr");
278 		return (NULL);
279 	}
280 
281 	/* Since this is an opaque pointer just cast it */
282 	return ((map_ctrl *)db);
283 }
284 
285 /*
286  * FUNCTION:	dup_map_ctrl()
287  *
288  * DESCRIPTION:	Duplicates a map_ctrl structure
289  *
290  * GIVEN :	Map_ctrl to duplicate
291  *
292  * RETURNS :	Pointer to a new malloced map_ctrl. CALLER MUST FREE
293  *		NULL on failure.
294  */
295 map_ctrl *
dup_map_ctrl(map_ctrl * old_map)296 dup_map_ctrl(map_ctrl *old_map)
297 {
298 	map_ctrl *new_map;
299 
300 	/*
301 	 * Could save a little bit of time by duplicating the static parts
302 	 * of the old map but on balance it is cleaner to just make a new one
303 	 * from scratch
304 	 */
305 	new_map = create_map_ctrl(old_map->map_path);
306 
307 	if (NULL == new_map)
308 		return (NULL);
309 
310 	/* If old map had open handles duplicate them */
311 	if (NULL != old_map->entries) {
312 		new_map->open_flags = old_map->open_flags;
313 		new_map->open_mode = old_map->open_mode;
314 		if (FAILURE == open_yptol_files(new_map)) {
315 			free_map_ctrl(new_map);
316 			return (NULL);
317 		}
318 	}
319 
320 	return (new_map);
321 }
322 
323 /*
324  * FUNCTION: 	free_map_crtl();
325  *
326  * DESCRIPTION: Free contents of a map_ctr structure and closed any open
327  *		DBM files.
328  *
329  * INPUTS:	Pointer to pointer to a map_ctrl.
330  *
331  * OUTPUTS:	Nothing
332  *
333  */
334 void
free_map_ctrl(map_ctrl * map)335 free_map_ctrl(map_ctrl *map)
336 {
337 
338 	if (NULL != map->entries) {
339 		dbm_close(map->entries);
340 		map->entries = NULL;
341 	}
342 
343 	if (NULL != map->map_name) {
344 		sfree(map->map_name);
345 		map->map_name = NULL;
346 	}
347 
348 	if (NULL != map->map_path) {
349 		sfree(map->map_path);
350 		map->map_path = NULL;
351 	}
352 
353 	if (NULL != map->domain) {
354 		sfree(map->domain);
355 		map->domain = NULL;
356 	}
357 
358 	if (yptol_mode) {
359 		if (NULL != map->ttl) {
360 			dbm_close(map->ttl);
361 			map->ttl = NULL;
362 		}
363 
364 		if (NULL != map->trad_map_path) {
365 			sfree(map->trad_map_path);
366 			map->trad_map_path = NULL;
367 		}
368 
369 		if (NULL != map->ttl_path) {
370 			sfree(map->ttl_path);
371 			map->ttl_path = NULL;
372 		}
373 
374 		if (NULL != map->key_data.dptr) {
375 			sfree(map->key_data.dptr);
376 			map->key_data.dptr = NULL;
377 			map->key_data.dsize = 0;
378 		}
379 	}
380 
381 	map->magic = 0;
382 
383 	/* Since map_ctrls are now always in malloced memory */
384 	sfree(map);
385 
386 }
387 
388 /*
389  * FUNCTION :	get_map_name()
390  *
391  * DESCRIPTION:	Get the name of a map from its map_ctrl. This could be done
392  *		as a simple dereference but this function hides the internal
393  *		implementation of map_ctrl from higher layers.
394  *
395  * GIVEN :	A map_ctrl pointer
396  *
397  * RETURNS :	A pointer to the map_ctrl. Higher levels treat this as an
398  *		opaque DBM pointer.
399  *		NULL on failure.
400  */
401 char *
get_map_name(DBM * db)402 get_map_name(DBM *db)
403 {
404 	map_ctrl *map = (map_ctrl *)db;
405 
406 	if (NULL == map)
407 		return (NULL);
408 
409 	return (map->map_name);
410 }
411 
412 /*
413  * FUNCTION :	set_key_data()
414  *
415  * DESCRIPTION:	Sets up the key data freeing any that already exists.
416  *
417  * GIVEN :	Pointer to the map_ctrl to set up.
418  *		Datum containing the key. The dptr of this will be set to
419  *		point to the key data.
420  *
421  * RETURNS :	Nothing
422  */
423 void
set_key_data(map_ctrl * map,datum * data)424 set_key_data(map_ctrl *map, datum *data)
425 {
426 	char *myself = "set_key_data";
427 
428 	/*
429 	 * Free up any existing key data. Because each dbm file can only have
430 	 * one enumeration going at a time this is safe.
431 	 */
432 	if (NULL != map->key_data.dptr) {
433 		sfree(map->key_data.dptr);
434 		map->key_data.dptr = NULL;
435 		map->key_data.dsize = 0;
436 	}
437 
438 	/* If nothing in key just return */
439 	if (NULL == data->dptr)
440 		return;
441 
442 	/* Something is in the key so must duplicate out of static memory */
443 	map->key_data.dptr = (char *)am(myself, data->dsize);
444 	if (NULL == map->key_data.dptr) {
445 		logmsg(MSG_NOMEM, LOG_ERR, "Cannot alloc memory for key data");
446 	} else {
447 		memcpy(map->key_data.dptr, data->dptr, data->dsize);
448 		map->key_data.dsize = data->dsize;
449 	}
450 
451 	/* Set datum to point to malloced version of the data */
452 	data->dptr = map->key_data.dptr;
453 
454 	return;
455 
456 }
457 
458 /*
459  * FUNCTION :	open_yptol_files()
460  *
461  * DESCRIPTION:	Opens both yptol files for a map. This is called both when a
462  *		map is opened and when it is reopened as a result of an update
463  *		operation. Must be called with map locked.
464  *
465  * GIVEN :	Initialized map_ctrl
466  *
467  * RETURNS :	SUCCESS = Maps opened
468  *		FAILURE = Maps not opened (and mess tidied up)
469  */
470 suc_code
open_yptol_files(map_ctrl * map)471 open_yptol_files(map_ctrl *map)
472 {
473 
474 	/* Open entries map */
475 	map->entries = dbm_open(map->map_path, map->open_flags, map->open_mode);
476 
477 	if (NULL == map->entries) {
478 		/* Maybe we were asked to open a non-existent map. No problem */
479 		return (FAILURE);
480 	}
481 
482 	if (yptol_mode) {
483 		/* Open TTLs map. Must always be writable */
484 		map->ttl = dbm_open(map->ttl_path, O_RDWR | O_CREAT, 0644);
485 		if (NULL == map->ttl) {
486 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
487 				"Cannot open TTL file %s", map->ttl_path);
488 			dbm_close(map->entries);
489 			map->entries = NULL;
490 			return (FAILURE);
491 		}
492 	}
493 
494 	return (SUCCESS);
495 }
496 
497 /*
498  * FUNCTION :   insert_map_in_list()
499  *
500  * DESCRIPTION:	add a map in map_id_list[]
501  *
502  * GIVEN :      map name
503  *              map unique ID
504  *
505  * RETURNS :	SUCCESS = map added
506  *		FAILURE = map not added
507  */
508 suc_code
insert_map_in_list(char * map_name,int unique_value)509 insert_map_in_list(char *map_name, int unique_value)
510 {
511 	int index;
512 	bool_t yptol_nl_sav = yptol_newlock;
513 	map_id_elt_t *new_elt;
514 
515 	/*
516 	 * Index in the hash table is computed from the original
517 	 * hash function: make sure yptol_newlock is set to false.
518 	 */
519 	yptol_newlock = FALSE;
520 	index = hash(map_name);
521 	yptol_newlock = yptol_nl_sav;
522 
523 	new_elt = (map_id_elt_t *)calloc(1, sizeof (map_id_elt_t));
524 	if (new_elt == NULL) {
525 		return (FAILURE);
526 	}
527 	new_elt->map_name = strdup(map_name);
528 	if (new_elt->map_name == NULL) { /* strdup() failed */
529 		sfree(new_elt);
530 		return (FAILURE);
531 	}
532 	new_elt->map_id = unique_value;
533 
534 	if (map_id_list[index] == NULL) {
535 		new_elt->next = NULL;
536 	} else {
537 		new_elt->next = map_id_list[index];
538 	}
539 	/* insert at begining */
540 	map_id_list[index] = new_elt;
541 
542 	return (SUCCESS);
543 }
544 
545 #ifdef NISDB_LDAP_DEBUG
546 /*
547  * FUNCTION :   dump_map_id_list()
548  *
549  * DESCRIPTION:	display max_map and dump map_id_list[]
550  *		not called, here for debug convenience only
551  *
552  * GIVEN :      nothing
553  *
554  * RETURNS :	nothing
555  */
556 void
dump_map_id_list()557 dump_map_id_list()
558 {
559 	int i;
560 	map_id_elt_t *cur_elt;
561 
562 	logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
563 		"dump_map_id_list: max_map is: %d, dumping map_idlist ...",
564 		max_map);
565 
566 	for (i = 0; i < MAXHASH; i++) {
567 		if (map_id_list[i] == NULL) {
568 			logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
569 				"no map for index %d", i);
570 		} else {
571 			logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
572 				"index %d has the following maps", i);
573 			cur_elt = map_id_list[i];
574 			do {
575 				logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
576 					"%s, unique id: %d",
577 					cur_elt->map_name,
578 					cur_elt->map_id);
579 				cur_elt = cur_elt->next;
580 			} while (cur_elt != NULL);
581 		}
582 	}
583 }
584 #endif
585 
586 /*
587  * FUNCTION :   free_map_id_list()
588  *
589  * DESCRIPTION:	free all previously allocated elements of map_id_list[]
590  *		reset max_map to 0
591  *
592  * GIVEN :      nothing
593  *
594  * RETURNS :	nothing
595  */
596 void
free_map_id_list()597 free_map_id_list()
598 {
599 	int i;
600 	map_id_elt_t *cur_elt, *next_elt;
601 
602 	for (i = 0; i < MAXHASH; i++) {
603 		if (map_id_list[i] != NULL) {
604 			cur_elt = map_id_list[i];
605 			do {
606 				next_elt = cur_elt->next;
607 				if (cur_elt->map_name)
608 					sfree(cur_elt->map_name);
609 				sfree(cur_elt);
610 				cur_elt = next_elt;
611 			} while (cur_elt != NULL);
612 			map_id_list[i] = NULL;
613 		}
614 	}
615 	max_map = 0;
616 }
617 
618 /*
619  * FUNCTION :   map_id_list_init()
620  *
621  * DESCRIPTION:	initializes map_id_list[] and max_map
622  *
623  * GIVEN :      nothing
624  *
625  * RETURNS :	 0 if OK
626  *		-1 if failure
627  */
628 int
map_id_list_init()629 map_id_list_init()
630 {
631 	char **domain_list, **map_list = NULL;
632 	int domain_num;
633 	int i, j;
634 	char *myself = "map_id_list_init";
635 	char mapbuf[MAXPATHLEN];
636 	int mapbuf_len = sizeof (mapbuf);
637 	int map_name_len;
638 	int seqnum = 0;
639 	int rc = 0;
640 
641 	for (i = 0; i < MAXHASH; i++) {
642 		map_id_list[i] = NULL;
643 	}
644 
645 	domain_num = get_mapping_domain_list(&domain_list);
646 	for (i = 0; i < domain_num; i++) {
647 		if (map_list) {
648 			free_map_list(map_list);
649 			map_list = NULL;
650 		}
651 
652 		/* get map list from mapping file */
653 		map_list = get_mapping_map_list(domain_list[i]);
654 		if (map_list == NULL) {
655 			/* no map for this domain in mapping file */
656 			logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
657 			    "%s: get_mapping_map_list()"
658 			    " found no map for domain %s",
659 			    myself, domain_list[i]);
660 		}
661 
662 		/* add maps from /var/yp/<domain> */
663 		if (add_map_domain_to_list(domain_list[i], &map_list) ==
664 		    FALSE) {
665 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
666 			    "%s: add_map_domain_to_list() failed", myself);
667 			free_map_id_list();
668 			if (map_list) free_map_list(map_list);
669 			return (-1);
670 		}
671 
672 		if (map_list == NULL || map_list[0] == NULL) {
673 			logmsg(MSG_NOTIMECHECK, LOG_DEBUG,
674 			    "%s: no map in domain %s",
675 			    myself, domain_list[i]);
676 			continue;
677 		}
678 
679 		for (j = 0; map_list[j] != NULL; j++) {
680 			/* build long name */
681 			map_name_len = ypdbpath_sz + 1 +
682 					strlen(domain_list[i]) + 1 +
683 					strlen(NTOL_PREFIX) +
684 					strlen(map_list[j]) + 1;
685 			if (map_name_len > mapbuf_len) {
686 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
687 				    "%s: map name too long for %s",
688 				    " in domain %s", myself, map_list[j],
689 				    domain_list[i]);
690 				free_map_id_list();
691 				if (map_list) free_map_list(map_list);
692 				return (-1);
693 			}
694 			(void) memset(mapbuf, 0, mapbuf_len);
695 			(void) snprintf(mapbuf, map_name_len, "%s%c%s%c%s%s",
696 				ypdbpath, SEP_CHAR, domain_list[i], SEP_CHAR,
697 				NTOL_PREFIX, map_list[j]);
698 
699 			if (insert_map_in_list(mapbuf, seqnum)
700 				    == FAILURE) {
701 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
702 				    "%s: failed to insert map %s",
703 				    " in domain %s", myself, map_list[j]);
704 				free_map_id_list();
705 				if (map_list) free_map_list(map_list);
706 				return (-1);
707 			}
708 			seqnum++;
709 		}
710 	}
711 
712 	max_map = seqnum;
713 
714 #ifdef NISDB_LDAP_DEBUG
715 	dump_map_id_list();
716 #endif
717 
718 	/*
719 	 * If more maps than allocated spaces in shared memory, that's a failure
720 	 * probably need to free previously allocated memory if failure,
721 	 * before returning.
722 	 */
723 	if (max_map > MAXHASH) {
724 		rc = -1;
725 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
726 		    "%s: too many maps (%d)",
727 		    myself, max_map);
728 		free_map_id_list();
729 	}
730 	if (map_list) free_map_list(map_list);
731 	return (rc);
732 }
733 
734 /*
735  * FUNCTION :   get_list_max()
736  *
737  * DESCRIPTION: return references to static variables map_id_list
738  *              and max_map;
739  *
740  * GIVEN :      address for referencing map_id_list
741  *              address for referencing max_map
742  *
743  * RETURNS :    nothing
744  */
745 void
get_list_max(map_id_elt_t *** list,int * max)746 get_list_max(map_id_elt_t ***list, int *max)
747 {
748 	*list = map_id_list;
749 	*max = max_map;
750 }
751