author | Jon Tibble <meths@btinternet.com> |
Thu, 09 Dec 2010 22:32:39 +0100 | |
changeset 13255 | 4afa820d78b9 |
parent 6812 | febeba71273d |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 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 |
*/ |
|
6812 | 21 |
|
0 | 22 |
/* |
6812 | 23 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
0 | 24 |
* Use is subject to license terms. |
25 |
*/ |
|
26 |
||
27 |
#pragma ident "%Z%%M% %I% %E% SMI" |
|
28 |
||
6812 | 29 |
#include "lint.h" |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
30 |
#include "file64.h" |
0 | 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> |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
37 |
#include <stdio_ext.h> |
0 | 38 |
#include <string.h> |
39 |
#include <ctype.h> |
|
40 |
#include <limits.h> |
|
41 |
#include <dlfcn.h> |
|
42 |
#include <errno.h> |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
43 |
#include "stdiom.h" |
0 | 44 |
|
45 |
#define __NSS_PRIVATE_INTERFACE |
|
46 |
#include "nsswitch_priv.h" |
|
47 |
#undef __NSS_PRIVATE_INTERFACE |
|
48 |
||
49 |
#include <syslog.h> |
|
50 |
||
51 |
#define islabel(c) (isalnum(c) || (c) == '_') |
|
52 |
||
53 |
#define LIBC_STRDUP(new, existing) \ |
|
54 |
if ((new = libc_strdup(existing)) == NULL) { \ |
|
55 |
dup_fail = 1; \ |
|
56 |
goto barf_line; \ |
|
57 |
} |
|
58 |
||
59 |
/* |
|
60 |
* This file has all the routines that access the configuration |
|
61 |
* information. |
|
62 |
*/ |
|
63 |
||
64 |
struct cons_cell_v1 { /* private to the parser */ |
|
65 |
struct __nsw_switchconfig_v1 *sw; |
|
66 |
struct cons_cell_v1 *next; |
|
67 |
}; |
|
68 |
||
69 |
struct cons_cell { /* private to the parser */ |
|
70 |
struct __nsw_switchconfig *sw; |
|
71 |
struct cons_cell *next; |
|
72 |
}; |
|
73 |
||
74 |
/* |
|
75 |
* Local routines |
|
76 |
*/ |
|
77 |
||
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 *); |
|
88 |
||
89 |
static struct cons_cell_v1 *concell_list_v1; /* stays with add_concell() */ |
|
90 |
static struct cons_cell *concell_list; /* stays with add_concell() */ |
|
91 |
||
92 |
/* |
|
93 |
* |
|
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] |
|
97 |
* |
|
98 |
* For backward compat, NIS via NIS server in DNS forwarding mode will be: |
|
99 |
* [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] |
|
100 |
* |
|
101 |
* And also for backward compat, the default criteria for DNS will be: |
|
102 |
* [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] |
|
103 |
*/ |
|
104 |
||
105 |
||
106 |
||
107 |
/* |
|
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. |
|
114 |
*/ |
|
115 |
static int dns_tryagain_retry = 3; |
|
116 |
||
117 |
/* |
|
118 |
* For backward compat (pre "lookup control"), the dns default behavior is |
|
119 |
* soft lookup. |
|
120 |
*/ |
|
121 |
static void |
|
122 |
set_dns_default_lkp(struct __nsw_lookup_v1 *lkp) |
|
123 |
{ |
|
124 |
if (strcasecmp(lkp->service_name, "dns") == 0) { |
|
6812 | 125 |
lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_NTIMES; |
0 | 126 |
lkp->max_retries = dns_tryagain_retry; |
127 |
} |
|
128 |
} |
|
129 |
||
130 |
/* |
|
131 |
* Private interface used by nss_common.c, hence this function is not static |
|
132 |
*/ |
|
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 */ |
|
137 |
{ |
|
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; |
|
143 |
||
144 |
*errp = __NSW_CONF_PARSE_SUCCESS; |
|
145 |
||
146 |
if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig_v1))) |
|
147 |
== NULL) { |
|
148 |
*errp = __NSW_CONF_PARSE_SYSERR; |
|
149 |
return (NULL); |
|
150 |
} |
|
151 |
LIBC_STRDUP(cfp->dbase, name); |
|
152 |
lkq = &cfp->lookups; |
|
153 |
||
154 |
/* linep points to a naming service name */ |
|
155 |
for (;;) { |
|
156 |
int i; |
|
157 |
||
158 |
/* white space following the last service */ |
|
159 |
if (*linep == '\0' || *linep == '\n') { |
|
160 |
return (cfp); |
|
161 |
} |
|
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); |
|
167 |
} |
|
168 |
||
169 |
*lkq = lkp; |
|
170 |
lkq = &lkp->next; |
|
171 |
||
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; |
|
179 |
||
180 |
/* get criteria for the naming service */ |
|
181 |
if (tokenp = skip(&linep, '[')) { /* got criteria */ |
|
182 |
||
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++; |
|
188 |
||
189 |
set_dns_default_lkp(lkp); |
|
190 |
||
191 |
end_crit = 0; |
|
192 |
||
193 |
/* linep points to a switch_err */ |
|
194 |
for (;;) { |
|
195 |
int ntimes = 0; /* try again max N times */ |
|
196 |
int dns_continue = 0; |
|
197 |
||
198 |
if ((tokenp = skip(&linep, '=')) == NULL) { |
|
199 |
goto barf_line; |
|
200 |
} |
|
201 |
||
202 |
/* premature end, ill char following = */ |
|
203 |
if (!islabel(*linep)) |
|
204 |
goto barf_line; |
|
205 |
||
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; |
|
223 |
} |
|
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) { |
|
233 |
/* |
|
234 |
* Add one more condition |
|
235 |
* so it retries only if it's |
|
236 |
* "dns [TRYAGAIN=continue]" |
|
237 |
*/ |
|
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; |
|
250 |
} |
|
251 |
else |
|
252 |
goto barf_line; |
|
253 |
||
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*/ |
|
281 |
/* |
|
282 |
* convert string tokenp to integer |
|
283 |
* and put in long_errs |
|
284 |
*/ |
|
285 |
} |
|
286 |
if (end_crit) { |
|
287 |
linep = spaceskip(p); |
|
288 |
if (*linep == '\0' || *linep == '\n') |
|
289 |
return (cfp); |
|
290 |
break; /* process next naming service */ |
|
291 |
} |
|
292 |
linep = p; |
|
293 |
} /* end of while loop for a name service's criteria */ |
|
294 |
} else { |
|
295 |
/* |
|
296 |
* no criteria for this naming service. |
|
297 |
* linep points to name service, but not null |
|
298 |
* terminated. |
|
299 |
*/ |
|
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); |
|
307 |
} |
|
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); |
|
315 |
} |
|
316 |
} /* end of while(1) loop for a name service */ |
|
317 |
||
318 |
barf_line: |
|
319 |
freeconf_v1(cfp); |
|
320 |
*errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY; |
|
321 |
return (NULL); |
|
322 |
} |
|
323 |
||
324 |
/* |
|
325 |
* Private interface used by nss_common.c, hence this function is not static |
|
326 |
*/ |
|
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 */ |
|
331 |
{ |
|
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; |
|
337 |
||
338 |
*errp = __NSW_CONF_PARSE_SUCCESS; |
|
339 |
||
340 |
if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig))) |
|
341 |
== NULL) { |
|
342 |
*errp = __NSW_CONF_PARSE_SYSERR; |
|
343 |
return (NULL); |
|
344 |
} |
|
345 |
LIBC_STRDUP(cfp->dbase, name); |
|
346 |
lkq = &cfp->lookups; |
|
347 |
||
348 |
/* linep points to a naming service name */ |
|
349 |
for (;;) { |
|
350 |
int i; |
|
351 |
||
352 |
/* white space following the last service */ |
|
353 |
if (*linep == '\0' || *linep == '\n') { |
|
354 |
return (cfp); |
|
355 |
} |
|
356 |
if ((lkp = libc_malloc(sizeof (struct __nsw_lookup))) |
|
357 |
== NULL) { |
|
358 |
*errp = __NSW_CONF_PARSE_SYSERR; |
|
359 |
freeconf(cfp); |
|
360 |
return (NULL); |
|
361 |
} |
|
362 |
||
363 |
*lkq = lkp; |
|
364 |
lkq = &lkp->next; |
|
365 |
||
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; |
|
371 |
||
372 |
/* get criteria for the naming service */ |
|
373 |
if (tokenp = skip(&linep, '[')) { /* got criteria */ |
|
374 |
||
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; |
|
381 |
||
382 |
/* linep points to a switch_err */ |
|
383 |
for (;;) { |
|
384 |
if ((tokenp = skip(&linep, '=')) == NULL) { |
|
385 |
goto barf_line; |
|
386 |
} |
|
387 |
||
388 |
/* premature end, ill char following = */ |
|
389 |
if (!islabel(*linep)) |
|
390 |
goto barf_line; |
|
391 |
||
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; |
|
409 |
} |
|
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) |
|
417 |
/* |
|
418 |
* =forever or =N might be in conf file |
|
419 |
* but old progs won't expect it. |
|
420 |
*/ |
|
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*/ |
|
440 |
/* |
|
441 |
* convert string tokenp to integer |
|
442 |
* and put in long_errs |
|
443 |
*/ |
|
444 |
} |
|
445 |
if (end_crit) { |
|
446 |
linep = spaceskip(p); |
|
447 |
if (*linep == '\0' || *linep == '\n') |
|
448 |
return (cfp); |
|
449 |
break; /* process next naming service */ |
|
450 |
} |
|
451 |
linep = p; |
|
452 |
} /* end of while loop for a name service's criteria */ |
|
453 |
} else { |
|
454 |
/* |
|
455 |
* no criteria for this naming service. |
|
456 |
* linep points to name service, but not null |
|
457 |
* terminated. |
|
458 |
*/ |
|
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); |
|
465 |
} |
|
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); |
|
472 |
} |
|
473 |
} /* end of while(1) loop for a name service */ |
|
474 |
||
475 |
barf_line: |
|
476 |
freeconf(cfp); |
|
477 |
*errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY; |
|
478 |
return (NULL); |
|
479 |
} |
|
480 |
||
481 |
static mutex_t serialize_config_v1 = DEFAULTMUTEX; |
|
482 |
static mutex_t serialize_config = DEFAULTMUTEX; |
|
483 |
||
484 |
static void |
|
485 |
syslog_warning(const char *dbase) |
|
486 |
{ |
|
487 |
syslog(LOG_WARNING, |
|
488 |
"libc: bad lookup policy for %s in %s, using defaults..\n", |
|
489 |
dbase, __NSW_CONFIG_FILE); |
|
490 |
} |
|
491 |
||
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
492 |
/* |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
493 |
* Since we cannot call malloc() or lock any of the ordinary mutexes |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
494 |
* while we hold an lmutex_lock(), we open the file outside the lock |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
495 |
* and disable locking on the file; the latter is fine because we're |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
496 |
* reading the fp only from a single thread. |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
497 |
*/ |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
498 |
static FILE * |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
499 |
open_conf(void) |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
500 |
{ |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
501 |
FILE *fp = fopen(__NSW_CONFIG_FILE, "rF"); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
502 |
|
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
503 |
if (fp != NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
504 |
if (_findbuf(fp) == NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
505 |
(void) fclose(fp); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
506 |
return (NULL); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
507 |
} |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
508 |
SET_IONOLOCK(fp); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
509 |
} |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
510 |
return (fp); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
511 |
} |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
512 |
|
0 | 513 |
struct __nsw_switchconfig_v1 * |
514 |
__nsw_getconfig_v1(const char *dbase, enum __nsw_parse_err *errp) |
|
515 |
{ |
|
516 |
struct __nsw_switchconfig_v1 *cfp, *retp = NULL; |
|
517 |
int syslog_error = 0; |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
518 |
FILE *fp = NULL; |
0 | 519 |
char *linep; |
520 |
char lineq[BUFSIZ]; |
|
521 |
||
522 |
lmutex_lock(&serialize_config_v1); |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
523 |
top: |
0 | 524 |
if (cfp = scrounge_cache_v1(dbase)) { |
525 |
*errp = __NSW_CONF_PARSE_SUCCESS; |
|
526 |
lmutex_unlock(&serialize_config_v1); |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
527 |
if (fp != NULL) |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
528 |
(void) fclose(fp); |
0 | 529 |
return (cfp); |
530 |
} |
|
531 |
||
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
532 |
if (fp == NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
533 |
struct cons_cell_v1 *cp = concell_list_v1; |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
534 |
|
0 | 535 |
lmutex_unlock(&serialize_config_v1); |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
536 |
/* open_conf() must be called w/o locks held */ |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
537 |
if ((fp = open_conf()) == NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
538 |
*errp = __NSW_CONF_PARSE_NOFILE; |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
539 |
return (NULL); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
540 |
} |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
541 |
lmutex_lock(&serialize_config_v1); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
542 |
/* Cache changed? */ |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
543 |
if (cp != concell_list_v1) |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
544 |
goto top; |
0 | 545 |
} |
546 |
||
547 |
*errp = __NSW_CONF_PARSE_NOPOLICY; |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
548 |
while (linep = fgets(lineq, BUFSIZ, fp)) { |
0 | 549 |
enum __nsw_parse_err line_err; |
550 |
char *tokenp, *comment; |
|
551 |
||
552 |
/* |
|
553 |
* Ignore portion of line following the comment character '#'. |
|
554 |
*/ |
|
555 |
if ((comment = strchr(linep, '#')) != NULL) { |
|
556 |
*comment = '\0'; |
|
557 |
} |
|
558 |
/* |
|
559 |
* skip past blank lines. |
|
560 |
* otherwise, cache as a struct switchconfig. |
|
561 |
*/ |
|
562 |
if ((*linep == '\0') || isspace(*linep)) { |
|
563 |
continue; |
|
564 |
} |
|
565 |
if ((tokenp = skip(&linep, ':')) == NULL) { |
|
566 |
continue; /* ignore this line */ |
|
567 |
} |
|
568 |
if (cfp = scrounge_cache_v1(tokenp)) { |
|
569 |
continue; /* ? somehow this database is in the cache */ |
|
570 |
} |
|
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; |
|
576 |
} |
|
577 |
} else { |
|
578 |
/* |
|
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. |
|
585 |
*/ |
|
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; |
|
594 |
} |
|
595 |
/* |
|
596 |
* Else blithely ignore problems on this line and |
|
597 |
* go ahead with the next line. |
|
598 |
*/ |
|
599 |
} |
|
600 |
} |
|
601 |
lmutex_unlock(&serialize_config_v1); |
|
602 |
/* |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
603 |
* We have to drop the lock before calling fclose()/syslog(). |
0 | 604 |
*/ |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
605 |
(void) fclose(fp); |
0 | 606 |
if (syslog_error) |
607 |
syslog_warning(dbase); |
|
608 |
return (retp); |
|
609 |
} |
|
610 |
||
611 |
struct __nsw_switchconfig * |
|
612 |
__nsw_getconfig(const char *dbase, enum __nsw_parse_err *errp) |
|
613 |
{ |
|
614 |
struct __nsw_switchconfig *cfp, *retp = NULL; |
|
615 |
int syslog_error = 0; |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
616 |
FILE *fp = NULL; |
0 | 617 |
char *linep; |
618 |
char lineq[BUFSIZ]; |
|
619 |
||
620 |
lmutex_lock(&serialize_config); |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
621 |
top: |
0 | 622 |
if (cfp = scrounge_cache(dbase)) { |
623 |
*errp = __NSW_CONF_PARSE_SUCCESS; |
|
624 |
lmutex_unlock(&serialize_config); |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
625 |
if (fp != NULL) |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
626 |
(void) fclose(fp); |
0 | 627 |
return (cfp); |
628 |
} |
|
629 |
||
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
630 |
if (fp == NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
631 |
struct cons_cell *cp = concell_list; |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
632 |
/* open_conf() must be called w/o locks held */ |
0 | 633 |
lmutex_unlock(&serialize_config); |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
634 |
if ((fp = open_conf()) == NULL) { |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
635 |
*errp = __NSW_CONF_PARSE_NOFILE; |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
636 |
return (NULL); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
637 |
} |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
638 |
lmutex_lock(&serialize_config); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
639 |
/* Cache changed? */ |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
640 |
if (cp != concell_list) |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
641 |
goto top; |
0 | 642 |
} |
643 |
||
644 |
*errp = __NSW_CONF_PARSE_NOPOLICY; |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
645 |
while (linep = fgets(lineq, BUFSIZ, fp)) { |
0 | 646 |
enum __nsw_parse_err line_err; |
647 |
char *tokenp, *comment; |
|
648 |
||
649 |
/* |
|
650 |
* Ignore portion of line following the comment character '#'. |
|
651 |
*/ |
|
652 |
if ((comment = strchr(linep, '#')) != NULL) { |
|
653 |
*comment = '\0'; |
|
654 |
} |
|
655 |
/* |
|
656 |
* skip past blank lines. |
|
657 |
* otherwise, cache as a struct switchconfig. |
|
658 |
*/ |
|
659 |
if ((*linep == '\0') || isspace(*linep)) { |
|
660 |
continue; |
|
661 |
} |
|
662 |
if ((tokenp = skip(&linep, ':')) == NULL) { |
|
663 |
continue; /* ignore this line */ |
|
664 |
} |
|
665 |
if (cfp = scrounge_cache(tokenp)) { |
|
666 |
continue; /* ? somehow this database is in the cache */ |
|
667 |
} |
|
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; |
|
673 |
} |
|
674 |
} else { |
|
675 |
/* |
|
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. |
|
682 |
*/ |
|
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; |
|
691 |
} |
|
692 |
/* |
|
693 |
* Else blithely ignore problems on this line and |
|
694 |
* go ahead with the next line. |
|
695 |
*/ |
|
696 |
} |
|
697 |
} |
|
698 |
lmutex_unlock(&serialize_config); |
|
699 |
/* |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
700 |
* We have to drop the lock before calling fclose()/syslog(). |
0 | 701 |
*/ |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
702 |
(void) fclose(fp); |
0 | 703 |
if (syslog_error) |
704 |
syslog_warning(dbase); |
|
705 |
return (retp); |
|
706 |
} |
|
707 |
||
708 |
||
709 |
static struct __nsw_switchconfig_v1 * |
|
710 |
scrounge_cache_v1(const char *dbase) |
|
711 |
{ |
|
712 |
struct cons_cell_v1 *cellp = concell_list_v1; |
|
713 |
||
714 |
for (; cellp; cellp = cellp->next) |
|
715 |
if (strcmp(dbase, cellp->sw->dbase) == 0) |
|
716 |
return (cellp->sw); |
|
717 |
return (NULL); |
|
718 |
} |
|
719 |
||
720 |
static struct __nsw_switchconfig * |
|
721 |
scrounge_cache(const char *dbase) |
|
722 |
{ |
|
723 |
struct cons_cell *cellp = concell_list; |
|
724 |
||
725 |
for (; cellp; cellp = cellp->next) |
|
726 |
if (strcmp(dbase, cellp->sw->dbase) == 0) |
|
727 |
return (cellp->sw); |
|
728 |
return (NULL); |
|
729 |
} |
|
730 |
||
731 |
static void |
|
732 |
freeconf_v1(struct __nsw_switchconfig_v1 *cfp) |
|
733 |
{ |
|
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); |
|
743 |
} |
|
744 |
} |
|
745 |
libc_free(cfp); |
|
746 |
} |
|
747 |
} |
|
748 |
||
749 |
static void |
|
750 |
freeconf(struct __nsw_switchconfig *cfp) |
|
751 |
{ |
|
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); |
|
761 |
} |
|
762 |
} |
|
763 |
libc_free(cfp); |
|
764 |
} |
|
765 |
} |
|
766 |
||
767 |
action_t |
|
768 |
__nsw_extended_action_v1(struct __nsw_lookup_v1 *lkp, int err) |
|
769 |
{ |
|
770 |
struct __nsw_long_err *lerrp; |
|
771 |
||
772 |
for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) { |
|
773 |
if (lerrp->nsw_errno == err) |
|
774 |
return (lerrp->action); |
|
775 |
} |
|
776 |
return (__NSW_CONTINUE); |
|
777 |
} |
|
778 |
||
779 |
action_t |
|
780 |
__nsw_extended_action(struct __nsw_lookup *lkp, int err) |
|
781 |
{ |
|
782 |
struct __nsw_long_err *lerrp; |
|
783 |
||
784 |
for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) { |
|
785 |
if (lerrp->nsw_errno == err) |
|
786 |
return (lerrp->action); |
|
787 |
} |
|
788 |
return (__NSW_CONTINUE); |
|
789 |
} |
|
790 |
||
791 |
||
792 |
/* give the next non-alpha character */ |
|
793 |
static char * |
|
794 |
labelskip(char *cur) |
|
795 |
{ |
|
796 |
char *p = cur; |
|
797 |
while (islabel(*p)) |
|
798 |
++p; |
|
799 |
return (p); |
|
800 |
} |
|
801 |
||
802 |
/* give the next non-space character */ |
|
803 |
static char * |
|
804 |
spaceskip(char *cur) |
|
805 |
{ |
|
806 |
char *p = cur; |
|
807 |
while (*p == ' ' || *p == '\t') |
|
808 |
++p; |
|
809 |
return (p); |
|
810 |
} |
|
811 |
||
812 |
/* |
|
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. |
|
819 |
*/ |
|
820 |
static char * |
|
821 |
skip(char **cur, char key) |
|
822 |
{ |
|
823 |
char *p, *tmp; |
|
824 |
char *q = *cur; |
|
825 |
int found, tmpfound; |
|
826 |
||
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 */ |
|
841 |
} |
|
842 |
} |
|
843 |
} |
|
844 |
if (!found) |
|
845 |
return (NULL); /* *cur unchanged */ |
|
846 |
*cur = p; |
|
847 |
return (q); |
|
848 |
} |
|
849 |
||
850 |
/* add to the front: LRU */ |
|
851 |
static int |
|
852 |
add_concell_v1(struct __nsw_switchconfig_v1 *cfp) |
|
853 |
{ |
|
854 |
struct cons_cell_v1 *cp; |
|
855 |
||
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); |
|
864 |
} |
|
865 |
||
866 |
/* add to the front: LRU */ |
|
867 |
static int |
|
868 |
add_concell(struct __nsw_switchconfig *cfp) |
|
869 |
{ |
|
870 |
struct cons_cell *cp; |
|
871 |
||
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); |
|
880 |
} |
|
881 |
||
882 |
int |
|
883 |
__nsw_freeconfig_v1(struct __nsw_switchconfig_v1 *conf) |
|
884 |
{ |
|
885 |
struct cons_cell_v1 *cellp; |
|
886 |
||
887 |
if (conf == NULL) { |
|
888 |
return (-1); |
|
889 |
} |
|
890 |
/* |
|
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. |
|
894 |
*/ |
|
895 |
lmutex_lock(&serialize_config_v1); |
|
896 |
for (cellp = concell_list_v1; cellp; cellp = cellp->next) { |
|
897 |
if (cellp->sw == conf) { |
|
898 |
break; |
|
899 |
} |
|
900 |
} |
|
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); |
|
909 |
} |
|
910 |
} |
|
911 |
||
912 |
int |
|
913 |
__nsw_freeconfig(struct __nsw_switchconfig *conf) |
|
914 |
{ |
|
915 |
struct cons_cell *cellp; |
|
916 |
||
917 |
if (conf == NULL) { |
|
918 |
return (-1); |
|
919 |
} |
|
920 |
/* |
|
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. |
|
924 |
*/ |
|
925 |
lmutex_lock(&serialize_config); |
|
926 |
for (cellp = concell_list; cellp; cellp = cellp->next) { |
|
927 |
if (cellp->sw == conf) { |
|
928 |
break; |
|
929 |
} |
|
930 |
} |
|
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); |
|
939 |
} |
|
940 |
} |
|
941 |
||
942 |
/* Return 1 if the string contains all digits, else return 0. */ |
|
943 |
static int |
|
944 |
alldigits(char *s) |
|
945 |
{ |
|
946 |
for (; *s; s++) |
|
947 |
if (!isdigit(*s)) |
|
948 |
return (0); |
|
949 |
return (1); |
|
950 |
} |