6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / gen / nsparse.c
blob57c07a7841c3f57e30aa2344b6a9f2393120222f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "lint.h"
30 #include "file64.h"
31 #include "mtlib.h"
32 #include "libc.h"
33 #include <synch.h>
34 #include <sys/types.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <stdio_ext.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <limits.h>
41 #include <dlfcn.h>
42 #include <errno.h>
43 #include "stdiom.h"
45 #define __NSS_PRIVATE_INTERFACE
46 #include "nsswitch_priv.h"
47 #undef __NSS_PRIVATE_INTERFACE
49 #include <syslog.h>
51 #define islabel(c) (isalnum(c) || (c) == '_')
53 #define LIBC_STRDUP(new, existing) \
54 if ((new = libc_strdup(existing)) == NULL) { \
55 dup_fail = 1; \
56 goto barf_line; \
60 * This file has all the routines that access the configuration
61 * information.
64 struct cons_cell_v1 { /* private to the parser */
65 struct __nsw_switchconfig_v1 *sw;
66 struct cons_cell_v1 *next;
69 struct cons_cell { /* private to the parser */
70 struct __nsw_switchconfig *sw;
71 struct cons_cell *next;
75 * Local routines
78 static char *skip(char **, char);
79 static char *labelskip(char *);
80 static char *spaceskip(char *);
81 static struct __nsw_switchconfig_v1 *scrounge_cache_v1(const char *);
82 static struct __nsw_switchconfig *scrounge_cache(const char *);
83 static int add_concell_v1(struct __nsw_switchconfig_v1 *);
84 static int add_concell(struct __nsw_switchconfig *);
85 static void freeconf_v1(struct __nsw_switchconfig_v1 *);
86 static void freeconf(struct __nsw_switchconfig *);
87 static int alldigits(char *);
89 static struct cons_cell_v1 *concell_list_v1; /* stays with add_concell() */
90 static struct cons_cell *concell_list; /* stays with add_concell() */
94 * With the "lookup control" feature, the default criteria for NIS, NIS+,
95 * and any new services (e.g. ldap) will be:
96 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=forever]
98 * For backward compat, NIS via NIS server in DNS forwarding mode will be:
99 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue]
101 * And also for backward compat, the default criteria for DNS will be:
102 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue]
108 * The BIND resolver normally will retry several times on server non-response.
109 * But now with the "lookup control" feature, we don't want the resolver doing
110 * many retries, rather we want it to return control (reasonably) quickly back
111 * to the switch engine. However, when TRYAGAIN=N or TRYAGAIN=forever is
112 * not explicitly set by the admin in the conf file, we want the old "resolver
113 * retry a few times" rather than no retries at all.
115 static int dns_tryagain_retry = 3;
118 * For backward compat (pre "lookup control"), the dns default behavior is
119 * soft lookup.
121 static void
122 set_dns_default_lkp(struct __nsw_lookup_v1 *lkp)
124 if (strcasecmp(lkp->service_name, "dns") == 0) {
125 lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_NTIMES;
126 lkp->max_retries = dns_tryagain_retry;
131 * Private interface used by nss_common.c, hence this function is not static
133 struct __nsw_switchconfig_v1 *
134 _nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp)
135 /* linep Nota Bene: not const char * */
136 /* errp Meanings are abused a bit */
138 struct __nsw_switchconfig_v1 *cfp;
139 struct __nsw_lookup_v1 *lkp, **lkq;
140 int end_crit, dup_fail = 0;
141 action_t act;
142 char *p, *tokenp;
144 *errp = __NSW_CONF_PARSE_SUCCESS;
146 if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig_v1)))
147 == NULL) {
148 *errp = __NSW_CONF_PARSE_SYSERR;
149 return (NULL);
151 LIBC_STRDUP(cfp->dbase, name);
152 lkq = &cfp->lookups;
154 /* linep points to a naming service name */
155 for (;;) {
156 int i;
158 /* white space following the last service */
159 if (*linep == '\0' || *linep == '\n') {
160 return (cfp);
162 if ((lkp = libc_malloc(sizeof (struct __nsw_lookup_v1)))
163 == NULL) {
164 *errp = __NSW_CONF_PARSE_SYSERR;
165 freeconf_v1(cfp);
166 return (NULL);
169 *lkq = lkp;
170 lkq = &lkp->next;
172 for (i = 0; i < __NSW_STD_ERRS_V1; i++)
173 if (i == __NSW_SUCCESS)
174 lkp->actions[i] = __NSW_RETURN;
175 else if (i == __NSW_TRYAGAIN)
176 lkp->actions[i] = __NSW_TRYAGAIN_FOREVER;
177 else
178 lkp->actions[i] = __NSW_CONTINUE;
180 /* get criteria for the naming service */
181 if (tokenp = skip(&linep, '[')) { /* got criteria */
183 /* premature end, illegal char following [ */
184 if (!islabel(*linep))
185 goto barf_line;
186 LIBC_STRDUP(lkp->service_name, tokenp);
187 cfp->num_lookups++;
189 set_dns_default_lkp(lkp);
191 end_crit = 0;
193 /* linep points to a switch_err */
194 for (;;) {
195 int ntimes = 0; /* try again max N times */
196 int dns_continue = 0;
198 if ((tokenp = skip(&linep, '=')) == NULL) {
199 goto barf_line;
202 /* premature end, ill char following = */
203 if (!islabel(*linep))
204 goto barf_line;
206 /* linep points to the string following '=' */
207 p = labelskip(linep);
208 if (*p == ']')
209 end_crit = 1;
210 else if (*p != ' ' && *p != '\t')
211 goto barf_line;
212 *p++ = '\0'; /* null terminate linep */
213 p = spaceskip(p);
214 if (!end_crit) {
215 if (*p == ']') {
216 end_crit = 1;
217 *p++ = '\0';
218 } else if (*p == '\0' || *p == '\n') {
219 return (cfp);
220 } else if (!islabel(*p))
221 /* p better be the next switch_err */
222 goto barf_line;
224 if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
225 act = __NSW_RETURN;
226 else if (strcasecmp(linep,
227 __NSW_STR_CONTINUE) == 0) {
228 if (strcasecmp(lkp->service_name,
229 "dns") == 0 &&
230 strcasecmp(tokenp,
231 __NSW_STR_TRYAGAIN)
232 == 0) {
234 * Add one more condition
235 * so it retries only if it's
236 * "dns [TRYAGAIN=continue]"
238 dns_continue = 1;
239 act = __NSW_TRYAGAIN_NTIMES;
240 } else
241 act = __NSW_CONTINUE;
242 } else if (strcasecmp(linep,
243 __NSW_STR_FOREVER) == 0)
244 act = __NSW_TRYAGAIN_FOREVER;
245 else if (alldigits(linep)) {
246 act = __NSW_TRYAGAIN_NTIMES;
247 ntimes = atoi(linep);
248 if (ntimes < 0 || ntimes > INT_MAX)
249 ntimes = 0;
251 else
252 goto barf_line;
254 if (__NSW_SUCCESS_ACTION(act) &&
255 strcasecmp(tokenp,
256 __NSW_STR_SUCCESS) == 0) {
257 lkp->actions[__NSW_SUCCESS] = act;
258 } else if (__NSW_NOTFOUND_ACTION(act) &&
259 strcasecmp(tokenp,
260 __NSW_STR_NOTFOUND) == 0) {
261 lkp->actions[__NSW_NOTFOUND] = act;
262 } else if (__NSW_UNAVAIL_ACTION(act) &&
263 strcasecmp(tokenp,
264 __NSW_STR_UNAVAIL) == 0) {
265 lkp->actions[__NSW_UNAVAIL] = act;
266 } else if (__NSW_TRYAGAIN_ACTION(act) &&
267 strcasecmp(tokenp,
268 __NSW_STR_TRYAGAIN) == 0) {
269 lkp->actions[__NSW_TRYAGAIN] = act;
270 if (strcasecmp(lkp->service_name,
271 "nis") == 0)
272 lkp->actions[
273 __NSW_NISSERVDNS_TRYAGAIN]
274 = act;
275 if (act == __NSW_TRYAGAIN_NTIMES)
276 lkp->max_retries =
277 dns_continue ?
278 dns_tryagain_retry : ntimes;
279 } else {
280 /*EMPTY*/
282 * convert string tokenp to integer
283 * and put in long_errs
286 if (end_crit) {
287 linep = spaceskip(p);
288 if (*linep == '\0' || *linep == '\n')
289 return (cfp);
290 break; /* process next naming service */
292 linep = p;
293 } /* end of while loop for a name service's criteria */
294 } else {
296 * no criteria for this naming service.
297 * linep points to name service, but not null
298 * terminated.
300 p = labelskip(linep);
301 if (*p == '\0' || *p == '\n') {
302 *p = '\0';
303 LIBC_STRDUP(lkp->service_name, linep);
304 set_dns_default_lkp(lkp);
305 cfp->num_lookups++;
306 return (cfp);
308 if (*p != ' ' && *p != '\t')
309 goto barf_line;
310 *p++ = '\0';
311 LIBC_STRDUP(lkp->service_name, linep);
312 set_dns_default_lkp(lkp);
313 cfp->num_lookups++;
314 linep = spaceskip(p);
316 } /* end of while(1) loop for a name service */
318 barf_line:
319 freeconf_v1(cfp);
320 *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY;
321 return (NULL);
325 * Private interface used by nss_common.c, hence this function is not static
327 struct __nsw_switchconfig *
328 _nsw_getoneconfig(const char *name, char *linep, enum __nsw_parse_err *errp)
329 /* linep Nota Bene: not const char * */
330 /* errp Meanings are abused a bit */
332 struct __nsw_switchconfig *cfp;
333 struct __nsw_lookup *lkp, **lkq;
334 int end_crit, dup_fail = 0;
335 action_t act;
336 char *p, *tokenp;
338 *errp = __NSW_CONF_PARSE_SUCCESS;
340 if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig)))
341 == NULL) {
342 *errp = __NSW_CONF_PARSE_SYSERR;
343 return (NULL);
345 LIBC_STRDUP(cfp->dbase, name);
346 lkq = &cfp->lookups;
348 /* linep points to a naming service name */
349 for (;;) {
350 int i;
352 /* white space following the last service */
353 if (*linep == '\0' || *linep == '\n') {
354 return (cfp);
356 if ((lkp = libc_malloc(sizeof (struct __nsw_lookup)))
357 == NULL) {
358 *errp = __NSW_CONF_PARSE_SYSERR;
359 freeconf(cfp);
360 return (NULL);
363 *lkq = lkp;
364 lkq = &lkp->next;
366 for (i = 0; i < __NSW_STD_ERRS; i++)
367 if (i == __NSW_SUCCESS)
368 lkp->actions[i] = 1;
369 else
370 lkp->actions[i] = 0;
372 /* get criteria for the naming service */
373 if (tokenp = skip(&linep, '[')) { /* got criteria */
375 /* premature end, illegal char following [ */
376 if (!islabel(*linep))
377 goto barf_line;
378 LIBC_STRDUP(lkp->service_name, tokenp);
379 cfp->num_lookups++;
380 end_crit = 0;
382 /* linep points to a switch_err */
383 for (;;) {
384 if ((tokenp = skip(&linep, '=')) == NULL) {
385 goto barf_line;
388 /* premature end, ill char following = */
389 if (!islabel(*linep))
390 goto barf_line;
392 /* linep points to the string following '=' */
393 p = labelskip(linep);
394 if (*p == ']')
395 end_crit = 1;
396 else if (*p != ' ' && *p != '\t')
397 goto barf_line;
398 *p++ = '\0'; /* null terminate linep */
399 p = spaceskip(p);
400 if (!end_crit) {
401 if (*p == ']') {
402 end_crit = 1;
403 *p++ = '\0';
404 } else if (*p == '\0' || *p == '\n')
405 return (cfp);
406 else if (!islabel(*p))
407 /* p better be the next switch_err */
408 goto barf_line;
410 if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
411 act = __NSW_RETURN;
412 else if (strcasecmp(linep,
413 __NSW_STR_CONTINUE) == 0)
414 act = __NSW_CONTINUE;
415 else if (strcasecmp(linep,
416 __NSW_STR_FOREVER) == 0)
418 * =forever or =N might be in conf file
419 * but old progs won't expect it.
421 act = __NSW_RETURN;
422 else if (alldigits(linep))
423 act = __NSW_CONTINUE;
424 else
425 goto barf_line;
426 if (strcasecmp(tokenp,
427 __NSW_STR_SUCCESS) == 0) {
428 lkp->actions[__NSW_SUCCESS] = act;
429 } else if (strcasecmp(tokenp,
430 __NSW_STR_NOTFOUND) == 0) {
431 lkp->actions[__NSW_NOTFOUND] = act;
432 } else if (strcasecmp(tokenp,
433 __NSW_STR_UNAVAIL) == 0) {
434 lkp->actions[__NSW_UNAVAIL] = act;
435 } else if (strcasecmp(tokenp,
436 __NSW_STR_TRYAGAIN) == 0) {
437 lkp->actions[__NSW_TRYAGAIN] = act;
438 } else {
439 /*EMPTY*/
441 * convert string tokenp to integer
442 * and put in long_errs
445 if (end_crit) {
446 linep = spaceskip(p);
447 if (*linep == '\0' || *linep == '\n')
448 return (cfp);
449 break; /* process next naming service */
451 linep = p;
452 } /* end of while loop for a name service's criteria */
453 } else {
455 * no criteria for this naming service.
456 * linep points to name service, but not null
457 * terminated.
459 p = labelskip(linep);
460 if (*p == '\0' || *p == '\n') {
461 *p = '\0';
462 LIBC_STRDUP(lkp->service_name, linep);
463 cfp->num_lookups++;
464 return (cfp);
466 if (*p != ' ' && *p != '\t')
467 goto barf_line;
468 *p++ = '\0';
469 LIBC_STRDUP(lkp->service_name, linep);
470 cfp->num_lookups++;
471 linep = spaceskip(p);
473 } /* end of while(1) loop for a name service */
475 barf_line:
476 freeconf(cfp);
477 *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY;
478 return (NULL);
481 static mutex_t serialize_config_v1 = DEFAULTMUTEX;
482 static mutex_t serialize_config = DEFAULTMUTEX;
484 static void
485 syslog_warning(const char *dbase)
487 syslog(LOG_WARNING,
488 "libc: bad lookup policy for %s in %s, using defaults..\n",
489 dbase, __NSW_CONFIG_FILE);
493 * Since we cannot call malloc() or lock any of the ordinary mutexes
494 * while we hold an lmutex_lock(), we open the file outside the lock
495 * and disable locking on the file; the latter is fine because we're
496 * reading the fp only from a single thread.
498 static FILE *
499 open_conf(void)
501 FILE *fp = fopen(__NSW_CONFIG_FILE, "rF");
503 if (fp != NULL) {
504 if (_findbuf(fp) == NULL) {
505 (void) fclose(fp);
506 return (NULL);
508 SET_IONOLOCK(fp);
510 return (fp);
513 struct __nsw_switchconfig_v1 *
514 __nsw_getconfig_v1(const char *dbase, enum __nsw_parse_err *errp)
516 struct __nsw_switchconfig_v1 *cfp, *retp = NULL;
517 int syslog_error = 0;
518 FILE *fp = NULL;
519 char *linep;
520 char lineq[BUFSIZ];
522 lmutex_lock(&serialize_config_v1);
523 top:
524 if (cfp = scrounge_cache_v1(dbase)) {
525 *errp = __NSW_CONF_PARSE_SUCCESS;
526 lmutex_unlock(&serialize_config_v1);
527 if (fp != NULL)
528 (void) fclose(fp);
529 return (cfp);
532 if (fp == NULL) {
533 struct cons_cell_v1 *cp = concell_list_v1;
535 lmutex_unlock(&serialize_config_v1);
536 /* open_conf() must be called w/o locks held */
537 if ((fp = open_conf()) == NULL) {
538 *errp = __NSW_CONF_PARSE_NOFILE;
539 return (NULL);
541 lmutex_lock(&serialize_config_v1);
542 /* Cache changed? */
543 if (cp != concell_list_v1)
544 goto top;
547 *errp = __NSW_CONF_PARSE_NOPOLICY;
548 while (linep = fgets(lineq, BUFSIZ, fp)) {
549 enum __nsw_parse_err line_err;
550 char *tokenp, *comment;
553 * Ignore portion of line following the comment character '#'.
555 if ((comment = strchr(linep, '#')) != NULL) {
556 *comment = '\0';
559 * skip past blank lines.
560 * otherwise, cache as a struct switchconfig.
562 if ((*linep == '\0') || isspace(*linep)) {
563 continue;
565 if ((tokenp = skip(&linep, ':')) == NULL) {
566 continue; /* ignore this line */
568 if (cfp = scrounge_cache_v1(tokenp)) {
569 continue; /* ? somehow this database is in the cache */
571 if (cfp = _nsw_getoneconfig_v1(tokenp, linep, &line_err)) {
572 (void) add_concell_v1(cfp);
573 if (strcmp(cfp->dbase, dbase) == 0) {
574 *errp = __NSW_CONF_PARSE_SUCCESS;
575 retp = cfp;
577 } else {
579 * Got an error on this line, if it is a system
580 * error we might as well give right now. If it
581 * is a parse error on the second entry of the
582 * database we are looking for and the first one
583 * was a good entry we end up logging the following
584 * syslog message and using a default policy instead.
586 if (line_err == __NSW_CONF_PARSE_SYSERR) {
587 *errp = __NSW_CONF_PARSE_SYSERR;
588 break;
589 } else if (line_err == __NSW_CONF_PARSE_NOPOLICY &&
590 strcmp(tokenp, dbase) == 0) {
591 syslog_error = 1;
592 *errp = __NSW_CONF_PARSE_NOPOLICY;
593 break;
596 * Else blithely ignore problems on this line and
597 * go ahead with the next line.
601 lmutex_unlock(&serialize_config_v1);
603 * We have to drop the lock before calling fclose()/syslog().
605 (void) fclose(fp);
606 if (syslog_error)
607 syslog_warning(dbase);
608 return (retp);
611 struct __nsw_switchconfig *
612 __nsw_getconfig(const char *dbase, enum __nsw_parse_err *errp)
614 struct __nsw_switchconfig *cfp, *retp = NULL;
615 int syslog_error = 0;
616 FILE *fp = NULL;
617 char *linep;
618 char lineq[BUFSIZ];
620 lmutex_lock(&serialize_config);
621 top:
622 if (cfp = scrounge_cache(dbase)) {
623 *errp = __NSW_CONF_PARSE_SUCCESS;
624 lmutex_unlock(&serialize_config);
625 if (fp != NULL)
626 (void) fclose(fp);
627 return (cfp);
630 if (fp == NULL) {
631 struct cons_cell *cp = concell_list;
632 /* open_conf() must be called w/o locks held */
633 lmutex_unlock(&serialize_config);
634 if ((fp = open_conf()) == NULL) {
635 *errp = __NSW_CONF_PARSE_NOFILE;
636 return (NULL);
638 lmutex_lock(&serialize_config);
639 /* Cache changed? */
640 if (cp != concell_list)
641 goto top;
644 *errp = __NSW_CONF_PARSE_NOPOLICY;
645 while (linep = fgets(lineq, BUFSIZ, fp)) {
646 enum __nsw_parse_err line_err;
647 char *tokenp, *comment;
650 * Ignore portion of line following the comment character '#'.
652 if ((comment = strchr(linep, '#')) != NULL) {
653 *comment = '\0';
656 * skip past blank lines.
657 * otherwise, cache as a struct switchconfig.
659 if ((*linep == '\0') || isspace(*linep)) {
660 continue;
662 if ((tokenp = skip(&linep, ':')) == NULL) {
663 continue; /* ignore this line */
665 if (cfp = scrounge_cache(tokenp)) {
666 continue; /* ? somehow this database is in the cache */
668 if (cfp = _nsw_getoneconfig(tokenp, linep, &line_err)) {
669 (void) add_concell(cfp);
670 if (strcmp(cfp->dbase, dbase) == 0) {
671 *errp = __NSW_CONF_PARSE_SUCCESS;
672 retp = cfp;
674 } else {
676 * Got an error on this line, if it is a system
677 * error we might as well give right now. If it
678 * is a parse error on the second entry of the
679 * database we are looking for and the first one
680 * was a good entry we end up logging the following
681 * syslog message and using a default policy instead.
683 if (line_err == __NSW_CONF_PARSE_SYSERR) {
684 *errp = __NSW_CONF_PARSE_SYSERR;
685 break;
686 } else if (line_err == __NSW_CONF_PARSE_NOPOLICY &&
687 strcmp(tokenp, dbase) == 0) {
688 syslog_error = 1;
689 *errp = __NSW_CONF_PARSE_NOPOLICY;
690 break;
693 * Else blithely ignore problems on this line and
694 * go ahead with the next line.
698 lmutex_unlock(&serialize_config);
700 * We have to drop the lock before calling fclose()/syslog().
702 (void) fclose(fp);
703 if (syslog_error)
704 syslog_warning(dbase);
705 return (retp);
709 static struct __nsw_switchconfig_v1 *
710 scrounge_cache_v1(const char *dbase)
712 struct cons_cell_v1 *cellp = concell_list_v1;
714 for (; cellp; cellp = cellp->next)
715 if (strcmp(dbase, cellp->sw->dbase) == 0)
716 return (cellp->sw);
717 return (NULL);
720 static struct __nsw_switchconfig *
721 scrounge_cache(const char *dbase)
723 struct cons_cell *cellp = concell_list;
725 for (; cellp; cellp = cellp->next)
726 if (strcmp(dbase, cellp->sw->dbase) == 0)
727 return (cellp->sw);
728 return (NULL);
731 static void
732 freeconf_v1(struct __nsw_switchconfig_v1 *cfp)
734 if (cfp) {
735 if (cfp->dbase)
736 libc_free(cfp->dbase);
737 if (cfp->lookups) {
738 struct __nsw_lookup_v1 *nex, *cur;
739 for (cur = cfp->lookups; cur; cur = nex) {
740 libc_free(cur->service_name);
741 nex = cur->next;
742 libc_free(cur);
745 libc_free(cfp);
749 static void
750 freeconf(struct __nsw_switchconfig *cfp)
752 if (cfp) {
753 if (cfp->dbase)
754 libc_free(cfp->dbase);
755 if (cfp->lookups) {
756 struct __nsw_lookup *nex, *cur;
757 for (cur = cfp->lookups; cur; cur = nex) {
758 libc_free(cur->service_name);
759 nex = cur->next;
760 libc_free(cur);
763 libc_free(cfp);
767 action_t
768 __nsw_extended_action_v1(struct __nsw_lookup_v1 *lkp, int err)
770 struct __nsw_long_err *lerrp;
772 for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) {
773 if (lerrp->nsw_errno == err)
774 return (lerrp->action);
776 return (__NSW_CONTINUE);
779 action_t
780 __nsw_extended_action(struct __nsw_lookup *lkp, int err)
782 struct __nsw_long_err *lerrp;
784 for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) {
785 if (lerrp->nsw_errno == err)
786 return (lerrp->action);
788 return (__NSW_CONTINUE);
792 /* give the next non-alpha character */
793 static char *
794 labelskip(char *cur)
796 char *p = cur;
797 while (islabel(*p))
798 ++p;
799 return (p);
802 /* give the next non-space character */
803 static char *
804 spaceskip(char *cur)
806 char *p = cur;
807 while (*p == ' ' || *p == '\t')
808 ++p;
809 return (p);
813 * terminate the *cur pointed string by null only if it is
814 * followed by "key" surrounded by zero or more spaces and
815 * return value is the same as the original *cur pointer and
816 * *cur pointer is advanced to the first non {space, key} char
817 * followed by the key. Otherwise, return NULL and keep
818 * *cur unchanged.
820 static char *
821 skip(char **cur, char key)
823 char *p, *tmp;
824 char *q = *cur;
825 int found, tmpfound;
827 tmp = labelskip(*cur);
828 p = tmp;
829 found = (*p == key);
830 if (found) {
831 *p++ = '\0'; /* overwrite the key */
832 p = spaceskip(p);
833 } else {
834 while (*p == ' ' || *p == '\t') {
835 tmpfound = (*++p == key);
836 if (tmpfound) {
837 found = tmpfound;
838 /* null terminate the return token */
839 *tmp = '\0';
840 p++; /* skip the key */
844 if (!found)
845 return (NULL); /* *cur unchanged */
846 *cur = p;
847 return (q);
850 /* add to the front: LRU */
851 static int
852 add_concell_v1(struct __nsw_switchconfig_v1 *cfp)
854 struct cons_cell_v1 *cp;
856 if (cfp == NULL)
857 return (1);
858 if ((cp = libc_malloc(sizeof (struct cons_cell_v1))) == NULL)
859 return (1);
860 cp->sw = cfp;
861 cp->next = concell_list_v1;
862 concell_list_v1 = cp;
863 return (0);
866 /* add to the front: LRU */
867 static int
868 add_concell(struct __nsw_switchconfig *cfp)
870 struct cons_cell *cp;
872 if (cfp == NULL)
873 return (1);
874 if ((cp = libc_malloc(sizeof (struct cons_cell))) == NULL)
875 return (1);
876 cp->sw = cfp;
877 cp->next = concell_list;
878 concell_list = cp;
879 return (0);
883 __nsw_freeconfig_v1(struct __nsw_switchconfig_v1 *conf)
885 struct cons_cell_v1 *cellp;
887 if (conf == NULL) {
888 return (-1);
891 * Hacked to make life easy for the code in nss_common.c. Free conf
892 * iff it was created by calling _nsw_getoneconfig() directly
893 * rather than by calling nsw_getconfig.
895 lmutex_lock(&serialize_config_v1);
896 for (cellp = concell_list_v1; cellp; cellp = cellp->next) {
897 if (cellp->sw == conf) {
898 break;
901 lmutex_unlock(&serialize_config_v1);
902 if (cellp == NULL) {
903 /* Not in the cache; free it */
904 freeconf_v1(conf);
905 return (1);
906 } else {
907 /* In the cache; don't free it */
908 return (0);
913 __nsw_freeconfig(struct __nsw_switchconfig *conf)
915 struct cons_cell *cellp;
917 if (conf == NULL) {
918 return (-1);
921 * Hacked to make life easy for the code in nss_common.c. Free conf
922 * iff it was created by calling _nsw_getoneconfig() directly
923 * rather than by calling nsw_getconfig.
925 lmutex_lock(&serialize_config);
926 for (cellp = concell_list; cellp; cellp = cellp->next) {
927 if (cellp->sw == conf) {
928 break;
931 lmutex_unlock(&serialize_config);
932 if (cellp == NULL) {
933 /* Not in the cache; free it */
934 freeconf(conf);
935 return (1);
936 } else {
937 /* In the cache; don't free it */
938 return (0);
942 /* Return 1 if the string contains all digits, else return 0. */
943 static int
944 alldigits(char *s)
946 for (; *s; s++)
947 if (!isdigit(*s))
948 return (0);
949 return (1);