1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23
24 /*
25 * string interface to confstr(),pathconf(),sysconf(),sysinfo()
26 * extended to allow some features to be set per-process
27 */
28
29 static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2009-07-02 $\0\n";
30
31 #include "univlib.h"
32
33 #include <ast.h>
34 #include <error.h>
35 #include <fs3d.h>
36 #include <ctype.h>
37 #include <regex.h>
38 #include <proc.h>
39
40 #include "conftab.h"
41 #include "FEATURE/libpath"
42
43 #ifndef DEBUG_astconf
44 #define DEBUG_astconf 0
45 #endif
46
47 #ifndef _pth_getconf
48 #undef ASTCONF_system
49 #define ASTCONF_system 0
50 #endif
51
52 #if _sys_systeminfo
53 # if !_lib_sysinfo
54 # if _lib_systeminfo
55 # define _lib_sysinfo 1
56 # define sysinfo(a,b,c) systeminfo(a,b,c)
57 # else
58 # if _lib_syscall && _sys_syscall
59 # include <sys/syscall.h>
60 # if defined(SYS_systeminfo)
61 # define _lib_sysinfo 1
62 # define sysinfo(a,b,c) syscall(SYS_systeminfo,a,b,c)
63 # endif
64 # endif
65 # endif
66 # endif
67 #else
68 # undef _lib_sysinfo
69 #endif
70
71 #define CONF_ERROR (CONF_USER<<0)
72 #define CONF_READONLY (CONF_USER<<1)
73 #define CONF_ALLOC (CONF_USER<<2)
74 #define CONF_GLOBAL (CONF_USER<<3)
75
76 #define DEFAULT(o) ((state.std||!dynamic[o].ast)?dynamic[o].std:dynamic[o].ast)
77 #define INITIALIZE() do{if(!state.data)synthesize(NiL,NiL,NiL);}while(0)
78 #define STANDARD(v) (streq(v,"standard")||streq(v,"strict")||streq(v,"posix")||streq(v,"xopen"))
79
80 #define MAXVAL 256
81
82 #if MAXVAL <= UNIV_SIZE
83 #undef MAXVAL
84 #define MAXVAL (UNIV_SIZE+1)
85 #endif
86
87 #ifndef _UNIV_DEFAULT
88 #define _UNIV_DEFAULT "att"
89 #endif
90
91 static char null[1];
92 static char root[2] = "/";
93
94 typedef struct Feature_s
95 {
96 struct Feature_s*next;
97 const char* name;
98 char* value;
99 char* std;
100 char* ast;
101 short length;
102 short standard;
103 unsigned int flags;
104 short op;
105 } Feature_t;
106
107 typedef struct
108 {
109 Conf_t* conf;
110 const char* name;
111 unsigned int flags;
112 short call;
113 short standard;
114 short section;
115 } Lookup_t;
116
117 static Feature_t dynamic[] =
118 {
119 #define OP_conformance 0
120 {
121 &dynamic[OP_conformance+1],
122 "CONFORMANCE",
123 "ast",
124 "standard",
125 "ast",
126 11,
127 CONF_AST,
128 0,
129 OP_conformance
130 },
131 #define OP_fs_3d 1
132 {
133 &dynamic[OP_fs_3d+1],
134 "FS_3D",
135 &null[0],
136 "0",
137 0,
138 5,
139 CONF_AST,
140 0,
141 OP_fs_3d
142 },
143 #define OP_getconf 2
144 {
145 &dynamic[OP_getconf+1],
146 "GETCONF",
147 #ifdef _pth_getconf
148 _pth_getconf,
149 #else
150 &null[0],
151 #endif
152 0,
153 0,
154 7,
155 CONF_AST,
156 CONF_READONLY,
157 OP_getconf
158 },
159 #define OP_hosttype 3
160 {
161 &dynamic[OP_hosttype+1],
162 "HOSTTYPE",
163 HOSTTYPE,
164 0,
165 0,
166 8,
167 CONF_AST,
168 CONF_READONLY,
169 OP_hosttype
170 },
171 #define OP_libpath 4
172 {
173 &dynamic[OP_libpath+1],
174 "LIBPATH",
175 #ifdef CONF_LIBPATH
176 CONF_LIBPATH,
177 #else
178 &null[0],
179 #endif
180 0,
181 0,
182 7,
183 CONF_AST,
184 0,
185 OP_libpath
186 },
187 #define OP_libprefix 5
188 {
189 &dynamic[OP_libprefix+1],
190 "LIBPREFIX",
191 #ifdef CONF_LIBPREFIX
192 CONF_LIBPREFIX,
193 #else
194 "lib",
195 #endif
196 0,
197 0,
198 9,
199 CONF_AST,
200 0,
201 OP_libprefix
202 },
203 #define OP_libsuffix 6
204 {
205 &dynamic[OP_libsuffix+1],
206 "LIBSUFFIX",
207 #ifdef CONF_LIBSUFFIX
208 CONF_LIBSUFFIX,
209 #else
210 ".so",
211 #endif
212 0,
213 0,
214 9,
215 CONF_AST,
216 0,
217 OP_libsuffix
218 },
219 #define OP_path_attributes 7
220 {
221 &dynamic[OP_path_attributes+1],
222 "PATH_ATTRIBUTES",
223 #if _WINIX
224 "c",
225 #else
226 &null[0],
227 #endif
228 &null[0],
229 0,
230 15,
231 CONF_AST,
232 CONF_READONLY,
233 OP_path_attributes
234 },
235 #define OP_path_resolve 8
236 {
237 &dynamic[OP_path_resolve+1],
238 "PATH_RESOLVE",
239 &null[0],
240 "physical",
241 "metaphysical",
242 12,
243 CONF_AST,
244 0,
245 OP_path_resolve
246 },
247 #define OP_universe 9
248 {
249 0,
250 "UNIVERSE",
251 &null[0],
252 "att",
253 0,
254 8,
255 CONF_AST,
256 0,
257 OP_universe
258 },
259 {
260 0
261 }
262 };
263
264 typedef struct
265 {
266
267 const char* id;
268 const char* name;
269 Feature_t* features;
270
271 int std;
272
273 /* default initialization from here down */
274
275 int prefix;
276 int synthesizing;
277
278 char* data;
279 char* last;
280
281 Feature_t* recent;
282
283 Ast_confdisc_f notify;
284
285 } State_t;
286
287 static State_t state = { "getconf", "_AST_FEATURES", dynamic, -1 };
288
289 static char* feature(const char*, const char*, const char*, unsigned int, Error_f);
290
291 /*
292 * return fmtbuf() copy of s
293 */
294
295 static char*
buffer(char * s)296 buffer(char* s)
297 {
298 return strcpy(fmtbuf(strlen(s) + 1), s);
299 }
300
301 /*
302 * synthesize state for fp
303 * fp==0 initializes from getenv(state.name)
304 * value==0 just does lookup
305 * otherwise state is set to value
306 */
307
308 static char*
synthesize(register Feature_t * fp,const char * path,const char * value)309 synthesize(register Feature_t* fp, const char* path, const char* value)
310 {
311 register char* s;
312 register char* d;
313 register char* v;
314 register char* p;
315 register int n;
316
317 #if DEBUG_astconf
318 if (fp)
319 error(-2, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp->name, path, value, fp, state.synthesizing ? " SYNTHESIZING" : "");
320 #endif
321 if (state.synthesizing)
322 return null;
323 if (!state.data)
324 {
325 char* se;
326 char* de;
327 char* ve;
328
329 state.prefix = strlen(state.name) + 1;
330 n = state.prefix + 3 * MAXVAL;
331 if (s = getenv(state.name))
332 n += strlen(s) + 1;
333 n = roundof(n, 32);
334 if (!(state.data = newof(0, char, n, 0)))
335 return 0;
336 state.last = state.data + n - 1;
337 strcpy(state.data, state.name);
338 state.data += state.prefix - 1;
339 *state.data++ = '=';
340 if (s)
341 strcpy(state.data, s);
342 ve = state.data;
343 state.synthesizing = 1;
344 for (;;)
345 {
346 for (s = ve; isspace(*s); s++);
347 for (d = s; *d && !isspace(*d); d++);
348 for (se = d; isspace(*d); d++);
349 for (v = d; *v && !isspace(*v); v++);
350 for (de = v; isspace(*v); v++);
351 if (!*v)
352 break;
353 for (ve = v; *ve && !isspace(*ve); ve++);
354 if (*ve)
355 *ve = 0;
356 else
357 ve = 0;
358 *de = 0;
359 *se = 0;
360 feature(s, d, v, 0, 0);
361 *se = ' ';
362 *de = ' ';
363 if (!ve)
364 break;
365 *ve++ = ' ';
366 }
367 state.synthesizing = 0;
368 }
369 if (!fp)
370 return state.data;
371 if (!state.last)
372 {
373 if (!value)
374 return 0;
375 n = strlen(value);
376 goto ok;
377 }
378 s = (char*)fp->name;
379 n = fp->length;
380 d = state.data;
381 for (;;)
382 {
383 while (isspace(*d))
384 d++;
385 if (!*d)
386 break;
387 if (strneq(d, s, n) && isspace(d[n]))
388 {
389 if (!value)
390 {
391 for (d += n + 1; *d && !isspace(*d); d++);
392 for (; isspace(*d); d++);
393 for (s = d; *s && !isspace(*s); s++);
394 n = s - d;
395 value = (const char*)d;
396 goto ok;
397 }
398 for (s = p = d + n + 1; *s && !isspace(*s); s++);
399 for (; isspace(*s); s++);
400 for (v = s; *s && !isspace(*s); s++);
401 n = s - v;
402 if ((!path || *path == *p && strlen(path) == (v - p - 1) && !memcmp(path, p, v - p - 1)) && strneq(v, value, n))
403 goto ok;
404 for (; isspace(*s); s++);
405 if (*s)
406 for (; *d = *s++; d++);
407 else if (d != state.data)
408 d--;
409 break;
410 }
411 for (; *d && !isspace(*d); d++);
412 for (; isspace(*d); d++);
413 for (; *d && !isspace(*d); d++);
414 for (; isspace(*d); d++);
415 for (; *d && !isspace(*d); d++);
416 }
417 if (!value)
418 {
419 if (!fp->op)
420 {
421 if (fp->flags & CONF_ALLOC)
422 fp->value[0] = 0;
423 else
424 fp->value = null;
425 }
426 return 0;
427 }
428 if (!value[0])
429 value = "0";
430 if (!path || !path[0] || path[0] == '/' && !path[1])
431 path = "-";
432 n += strlen(path) + strlen(value) + 3;
433 if (d + n >= state.last)
434 {
435 int c;
436 int i;
437
438 i = d - state.data;
439 state.data -= state.prefix;
440 c = n + state.last - state.data + 3 * MAXVAL;
441 c = roundof(c, 32);
442 if (!(state.data = newof(state.data, char, c, 0)))
443 return 0;
444 state.last = state.data + c - 1;
445 state.data += state.prefix;
446 d = state.data + i;
447 }
448 if (d != state.data)
449 *d++ = ' ';
450 for (s = (char*)fp->name; *d = *s++; d++);
451 *d++ = ' ';
452 for (s = (char*)path; *d = *s++; d++);
453 *d++ = ' ';
454 for (s = (char*)value; *d = *s++; d++);
455 #if DEBUG_astconf
456 error(-3, "astconf synthesize %s", state.data - state.prefix);
457 #endif
458 setenviron(state.data - state.prefix);
459 if (state.notify)
460 (*state.notify)(NiL, NiL, state.data - state.prefix);
461 n = s - (char*)value - 1;
462 ok:
463 if (!(fp->flags & CONF_ALLOC))
464 fp->value = 0;
465 if (n == 1 && (*value == '0' || *value == '-'))
466 n = 0;
467 if (!(fp->value = newof(fp->value, char, n, 1)))
468 fp->value = null;
469 else
470 {
471 fp->flags |= CONF_ALLOC;
472 memcpy(fp->value, value, n);
473 fp->value[n] = 0;
474 }
475 return fp->value;
476 }
477
478 /*
479 * initialize the value for fp
480 * if command!=0 then it is checked for on $PATH
481 * synthesize(fp,path,succeed) called on success
482 * otherwise synthesize(fp,path,fail) called
483 */
484
485 static void
initialize(register Feature_t * fp,const char * path,const char * command,const char * succeed,const char * fail)486 initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
487 {
488 register char* p;
489 register int ok = 1;
490
491 #if DEBUG_astconf
492 error(-2, "astconf initialize name=%s path=%s command=%s succeed=%s fail=%s fp=%p%s", fp->name, path, command, succeed, fail, fp, state.synthesizing ? " SYNTHESIZING" : "");
493 #endif
494 switch (fp->op)
495 {
496 case OP_conformance:
497 ok = getenv("POSIXLY_CORRECT") != 0;
498 break;
499 case OP_hosttype:
500 ok = 1;
501 break;
502 case OP_path_attributes:
503 ok = 1;
504 break;
505 case OP_path_resolve:
506 ok = fs3d(FS3D_TEST);
507 break;
508 case OP_universe:
509 ok = streq(_UNIV_DEFAULT, DEFAULT(OP_universe));
510 /*FALLTHROUGH...*/
511 default:
512 if (p = getenv("PATH"))
513 {
514 register int r = 1;
515 register char* d = p;
516 Sfio_t* tmp;
517
518 #if DEBUG_astconf
519 error(-2, "astconf initialize name=%s ok=%d PATH=%s", fp->name, ok, p);
520 #endif
521 if (tmp = sfstropen())
522 {
523 for (;;)
524 {
525 switch (*p++)
526 {
527 case 0:
528 break;
529 case ':':
530 if (command && (fp->op != OP_universe || !ok))
531 {
532 if (r = p - d - 1)
533 {
534 sfwrite(tmp, d, r);
535 sfputc(tmp, '/');
536 sfputr(tmp, command, 0);
537 if ((d = sfstruse(tmp)) && !eaccess(d, X_OK))
538 {
539 ok = 1;
540 if (fp->op != OP_universe)
541 break;
542 }
543 }
544 d = p;
545 }
546 r = 1;
547 continue;
548 case '/':
549 if (r)
550 {
551 r = 0;
552 if (fp->op == OP_universe)
553 {
554 if (p[0] == 'u' && p[1] == 's' && p[2] == 'r' && p[3] == '/')
555 for (p += 4; *p == '/'; p++);
556 if (p[0] == 'b' && p[1] == 'i' && p[2] == 'n')
557 {
558 for (p += 3; *p == '/'; p++);
559 if (!*p || *p == ':')
560 break;
561 }
562 }
563 }
564 if (fp->op == OP_universe)
565 {
566 if (strneq(p, "xpg", 3) || strneq(p, "5bin", 4))
567 {
568 ok = 1;
569 break;
570 }
571 if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
572 {
573 ok = 0;
574 break;
575 }
576 }
577 continue;
578 default:
579 r = 0;
580 continue;
581 }
582 break;
583 }
584 sfclose(tmp);
585 }
586 else
587 ok = 1;
588 }
589 break;
590 }
591 #if DEBUG_astconf
592 error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s ok=%d", __LINE__, state.std, fp->name, ok ? succeed : fail, fp->std, fp->ast, fp->value, ok);
593 #endif
594 synthesize(fp, path, ok ? succeed : fail);
595 }
596
597 /*
598 * format synthesized value
599 */
600
601 static char*
format(register Feature_t * fp,const char * path,const char * value,unsigned int flags,Error_f conferror)602 format(register Feature_t* fp, const char* path, const char* value, unsigned int flags, Error_f conferror)
603 {
604 register Feature_t* sp;
605 register int n;
606
607 #if DEBUG_astconf
608 error(-2, "astconf format name=%s path=%s value=%s flags=%04x fp=%p%s", fp->name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
609 #endif
610 if (value)
611 fp->flags &= ~CONF_GLOBAL;
612 else if (fp->flags & CONF_GLOBAL)
613 return fp->value;
614 switch (fp->op)
615 {
616
617 case OP_conformance:
618 if (value && STANDARD(value))
619 value = fp->std;
620 n = state.std = streq(fp->value, fp->std);
621 #if DEBUG_astconf
622 error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
623 #endif
624 if (!synthesize(fp, path, value))
625 initialize(fp, path, NiL, fp->std, fp->value);
626 #if DEBUG_astconf
627 error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
628 #endif
629 if (!n && STANDARD(fp->value))
630 {
631 state.std = 1;
632 for (sp = state.features; sp; sp = sp->next)
633 if (sp->std && sp->op && sp->op != OP_conformance)
634 astconf(sp->name, path, sp->std);
635 }
636 #if DEBUG_astconf
637 error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
638 #endif
639 break;
640
641 case OP_fs_3d:
642 fp->value = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? "1" : null;
643 break;
644
645 case OP_hosttype:
646 break;
647
648 case OP_path_attributes:
649 #ifdef _PC_PATH_ATTRIBUTES
650 {
651 register char* s;
652 register char* e;
653 intmax_t v;
654
655 /*
656 * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
657 */
658
659 if ((v = pathconf(path, _PC_PATH_ATTRIBUTES)) == -1L)
660 return 0;
661 s = fp->value;
662 e = s + sizeof(fp->value) - 1;
663 for (n = 'a'; n <= 'z'; n++)
664 if (v & (1 << (n - 'a')))
665 {
666 *s++ = n;
667 if (s >= e)
668 break;
669 }
670 *s = 0;
671 }
672 #endif
673 break;
674
675 case OP_path_resolve:
676 if (!synthesize(fp, path, value))
677 initialize(fp, path, NiL, "logical", DEFAULT(OP_path_resolve));
678 break;
679
680 case OP_universe:
681 #if _lib_universe
682 if (getuniverse(fp->value) < 0)
683 strcpy(fp->value, DEFAULT(OP_universe));
684 if (value)
685 setuniverse(value);
686 #else
687 #ifdef UNIV_MAX
688 n = 0;
689 if (value)
690 {
691 while (n < univ_max && !streq(value, univ_name[n])
692 n++;
693 if (n >= univ_max)
694 {
695 if (conferror)
696 (*conferror)(&state, &state, 2, "%s: %s: universe value too large", fp->name, value);
697 return 0;
698 }
699 }
700 #ifdef ATT_UNIV
701 n = setuniverse(n + 1);
702 if (!value && n > 0)
703 setuniverse(n);
704 #else
705 n = universe(value ? n + 1 : U_GET);
706 #endif
707 if (n <= 0 || n >= univ_max)
708 n = 1;
709 strcpy(fp->value, univ_name[n - 1]);
710 #else
711 if (value && streq(path, "="))
712 {
713 if (state.synthesizing)
714 {
715 if (!(fp->flags & CONF_ALLOC))
716 fp->value = 0;
717 n = strlen(value);
718 if (!(fp->value = newof(fp->value, char, n, 1)))
719 fp->value = null;
720 else
721 {
722 fp->flags |= CONF_ALLOC;
723 memcpy(fp->value, value, n);
724 fp->value[n] = 0;
725 }
726 }
727 else
728 synthesize(fp, path, value);
729 }
730 else
731 initialize(fp, path, "echo", DEFAULT(OP_universe), "ucb");
732 #endif
733 #endif
734 break;
735
736 default:
737 synthesize(fp, path, value);
738 break;
739
740 }
741 if (streq(path, "="))
742 fp->flags |= CONF_GLOBAL;
743 return fp->value;
744 }
745
746 /*
747 * value==0 get feature name
748 * value!=0 set feature name
749 * 0 returned if error or not defined; otherwise previous value
750 */
751
752 static char*
753 feature(const char* name, const char* path, const char* value, unsigned int flags, Error_f conferror)
754 {
755 register Feature_t* fp;
756 register int n;
757
758 if (value && (streq(value, "-") || streq(value, "0")))
759 value = null;
760 for (fp = state.features; fp && !streq(fp->name, name); fp = fp->next);
761 #if DEBUG_astconf
762 error(-2, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
763 #endif
764 if (!fp)
765 {
766 if (!value)
767 return 0;
768 if (state.notify && !(*state.notify)(name, path, value))
769 return 0;
770 n = strlen(name);
771 if (!(fp = newof(0, Feature_t, 1, n + 1)))
772 {
773 if (conferror)
774 (*conferror)(&state, &state, 2, "%s: out of space", name);
775 return 0;
776 }
777 fp->op = -1;
778 fp->name = (const char*)fp + sizeof(Feature_t);
779 strcpy((char*)fp->name, name);
780 fp->length = n;
781 fp->std = &null[0];
782 fp->next = state.features;
783 state.features = fp;
784 }
785 else if (value)
786 {
787 if (fp->flags & CONF_READONLY)
788 {
789 if (conferror)
790 (*conferror)(&state, &state, 2, "%s: cannot set readonly symbol", fp->name);
791 return 0;
792 }
793 if (state.notify && !streq(fp->value, value) && !(*state.notify)(name, path, value))
794 return 0;
795 }
796 else
797 state.recent = fp;
798 return format(fp, path, value, flags, conferror);
799 }
800
801 /*
802 * binary search for name in conf[]
803 */
804
805 static int
806 lookup(register Lookup_t* look, const char* name, unsigned int flags)
807 {
808 register Conf_t* mid = (Conf_t*)conf;
809 register Conf_t* lo = mid;
810 register Conf_t* hi = mid + conf_elements;
811 register int v;
812 register int c;
813 char* e;
814 const Prefix_t* p;
815
816 static Conf_t num;
817
818 look->flags = 0;
819 look->call = -1;
820 look->standard = (flags & ASTCONF_AST) ? CONF_AST : -1;
821 look->section = -1;
822 while (*name == '_')
823 name++;
824 again:
825 for (p = prefix; p < &prefix[prefix_elements]; p++)
826 if (strneq(name, p->name, p->length) && ((c = name[p->length] == '_' || name[p->length] == '(' || name[p->length] == '#') || (v = isdigit(name[p->length]) && name[p->length + 1] == '_')))
827 {
828 if (p->call < 0)
829 {
830 if (look->standard >= 0)
831 break;
832 look->standard = p->standard;
833 }
834 else
835 {
836 if (look->call >= 0)
837 break;
838 look->call = p->call;
839 }
840 if (name[p->length] == '(' || name[p->length] == '#')
841 {
842 look->conf = #
843 strncpy((char*)num.name, name, sizeof(num.name));
844 num.call = p->call;
845 num.flags = *name == 'C' ? CONF_STRING : 0;
846 num.op = (short)strtol(name + p->length + 1, &e, 10);
847 if (name[p->length] == '(' && *e == ')')
848 e++;
849 if (*e)
850 break;
851 return 1;
852 }
853 name += p->length + c;
854 if (look->section < 0 && !c && v)
855 {
856 look->section = name[0] - '0';
857 name += 2;
858 }
859 goto again;
860 }
861 #if HUH_2006_02_10
862 if (look->section < 0)
863 look->section = 1;
864 #endif
865 look->name = name;
866 #if DEBUG_astconf
867 error(-2, "astconf normal name=%s standard=%d section=%d call=%d flags=%04x elements=%d", look->name, look->standard, look->section, look->call, flags, conf_elements);
868 #endif
869 c = *((unsigned char*)name);
870 while (lo <= hi)
871 {
872 mid = lo + (hi - lo) / 2;
873 #if DEBUG_astconf
874 error(-3, "astconf lookup name=%s mid=%s", name, mid->name);
875 #endif
876 if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
877 {
878 hi = mid;
879 lo = (Conf_t*)conf;
880 do
881 {
882 if ((look->standard < 0 || look->standard == mid->standard) &&
883 (look->section < 0 || look->section == mid->section) &&
884 (look->call < 0 || look->call == mid->call))
885 goto found;
886 } while (mid-- > lo && streq(mid->name, look->name));
887 mid = hi;
888 hi = lo + conf_elements - 1;
889 while (++mid < hi && streq(mid->name, look->name))
890 {
891 if ((look->standard < 0 || look->standard == mid->standard) &&
892 (look->section < 0 || look->section == mid->section) &&
893 (look->call < 0 || look->call == mid->call))
894 goto found;
895 }
896 break;
897 }
898 else if (v > 0)
899 lo = mid + 1;
900 else
901 hi = mid - 1;
902 }
903 return 0;
904 found:
905 if (look->call < 0 && look->standard >= 0 && (look->section <= 1 || (mid->flags & CONF_MINMAX)))
906 look->flags |= CONF_MINMAX;
907 look->conf = mid;
908 #if DEBUG_astconf
909 error(-2, "astconf lookup name=%s standard=%d:%d section=%d:%d call=%d:%d", look->name, look->standard, mid->standard, look->section, mid->section, look->call, mid->call);
910 #endif
911 return 1;
912 }
913
914 /*
915 * return a tolower'd copy of s
916 */
917
918 static char*
919 fmtlower(register const char* s)
920 {
921 register int c;
922 register char* t;
923 char* b;
924
925 b = t = fmtbuf(strlen(s) + 1);
926 while (c = *s++)
927 {
928 if (isupper(c))
929 c = tolower(c);
930 *t++ = c;
931 }
932 *t = 0;
933 return b;
934 }
935
936 /*
937 * print value line for p
938 * if !name then value prefixed by "p->name="
939 * if (flags & CONF_MINMAX) then default minmax value used
940 */
941
942 static char*
943 print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
944 {
945 register Conf_t* p = look->conf;
946 register unsigned int flags = look->flags;
947 char* call;
948 char* f;
949 const char* s;
950 int i;
951 int n;
952 int olderrno;
953 int drop;
954 int defined;
955 intmax_t v;
956 char buf[PATH_MAX];
957 char flg[16];
958
959 if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
960 flags |= CONF_PREFIXED;
961 olderrno = errno;
962 errno = 0;
963 #if DEBUG_astconf
964 error(-1, "astconf name=%s:%s:%s standard=%d section=%d call=%s op=%d flags=|%s%s%s%s%s:|%s%s%s%s%s%s%s%s%s%s"
965 , name, look->name, p->name, p->standard, p->section, prefix[p->call + CONF_call].name, p->op
966 , (flags & CONF_FEATURE) ? "FEATURE|" : ""
967 , (flags & CONF_LIMIT) ? "LIMIT|" : ""
968 , (flags & CONF_MINMAX) ? "MINMAX|" : ""
969 , (flags & CONF_PREFIXED) ? "PREFIXED|" : ""
970 , (flags & CONF_STRING) ? "STRING|" : ""
971 , (p->flags & CONF_DEFER_CALL) ? "DEFER_CALL|" : ""
972 , (p->flags & CONF_DEFER_MM) ? "DEFER_MM|" : ""
973 , (p->flags & CONF_FEATURE) ? "FEATURE|" : ""
974 , (p->flags & CONF_LIMIT_DEF) ? "LIMIT_DEF|" : (p->flags & CONF_LIMIT) ? "LIMIT|" : ""
975 , (p->flags & CONF_MINMAX_DEF) ? "MINMAX_DEF|" : (p->flags & CONF_MINMAX) ? "MINMAX|" : ""
976 , (p->flags & CONF_NOUNDERSCORE) ? "NOUNDERSCORE|" : ""
977 , (p->flags & CONF_PREFIXED) ? "PREFIXED|" : ""
978 , (p->flags & CONF_PREFIX_ONLY) ? "PREFIX_ONLY|" : ""
979 , (p->flags & CONF_STANDARD) ? "STANDARD|" : ""
980 , (p->flags & CONF_STRING) ? "STRING|" : ""
981 , (p->flags & CONF_UNDERSCORE) ? "UNDERSCORE|" : ""
982 );
983 #endif
984 flags |= CONF_LIMIT_DEF|CONF_MINMAX_DEF;
985 if (conferror && name)
986 {
987 if ((p->flags & CONF_PREFIX_ONLY) && look->standard < 0)
988 goto bad;
989 if (!(flags & CONF_MINMAX) || !(p->flags & CONF_MINMAX))
990 {
991 switch (p->call)
992 {
993 case CONF_pathconf:
994 if (path == root)
995 {
996 (*conferror)(&state, &state, 2, "%s: path expected", name);
997 goto bad;
998 }
999 break;
1000 default:
1001 if (path != root)
1002 {
1003 (*conferror)(&state, &state, 2, "%s: path not expected", name);
1004 goto bad;
1005 }
1006 break;
1007 }
1008 #ifdef _pth_getconf
1009 if (p->flags & CONF_DEFER_CALL)
1010 goto bad;
1011 #endif
1012 }
1013 else
1014 {
1015 if (path != root)
1016 {
1017 (*conferror)(&state, &state, 2, "%s: path not expected", name);
1018 goto bad;
1019 }
1020 #ifdef _pth_getconf
1021 if ((p->flags & CONF_DEFER_MM) || !(p->flags & CONF_MINMAX_DEF))
1022 goto bad;
1023 #endif
1024 }
1025 if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
1026 goto bad;
1027 }
1028 s = 0;
1029 defined = 1;
1030 switch (i = (p->op < 0 || (flags & CONF_MINMAX) && (p->flags & CONF_MINMAX_DEF)) ? 0 : p->call)
1031 {
1032 case CONF_confstr:
1033 call = "confstr";
1034 #if _lib_confstr
1035 if (!(v = confstr(p->op, buf, sizeof(buf))))
1036 {
1037 defined = 0;
1038 v = -1;
1039 errno = EINVAL;
1040 }
1041 else if (v > 0)
1042 {
1043 buf[sizeof(buf) - 1] = 0;
1044 s = (const char*)buf;
1045 }
1046 else
1047 defined = 0;
1048 break;
1049 #else
1050 goto predef;
1051 #endif
1052 case CONF_pathconf:
1053 call = "pathconf";
1054 #if _lib_pathconf
1055 if ((v = pathconf(path, p->op)) < 0)
1056 defined = 0;
1057 break;
1058 #else
1059 goto predef;
1060 #endif
1061 case CONF_sysconf:
1062 call = "sysconf";
1063 #if _lib_sysconf
1064 if ((v = sysconf(p->op)) < 0)
1065 defined = 0;
1066 break;
1067 #else
1068 goto predef;
1069 #endif
1070 case CONF_sysinfo:
1071 call = "sysinfo";
1072 #if _lib_sysinfo
1073 if ((v = sysinfo(p->op, buf, sizeof(buf))) >= 0)
1074 {
1075 buf[sizeof(buf) - 1] = 0;
1076 s = (const char*)buf;
1077 }
1078 else
1079 defined = 0;
1080 break;
1081 #else
1082 goto predef;
1083 #endif
1084 default:
1085 call = "synthesis";
1086 errno = EINVAL;
1087 v = -1;
1088 defined = 0;
1089 break;
1090 case 0:
1091 call = 0;
1092 if (p->standard == CONF_AST)
1093 {
1094 if (streq(p->name, "RELEASE") && (i = open("/proc/version", O_RDONLY)) >= 0)
1095 {
1096 n = read(i, buf, sizeof(buf) - 1);
1097 close(i);
1098 if (n > 0 && buf[n - 1] == '\n')
1099 n--;
1100 if (n > 0 && buf[n - 1] == '\r')
1101 n--;
1102 buf[n] = 0;
1103 if (buf[0])
1104 {
1105 v = 0;
1106 s = buf;
1107 break;
1108 }
1109 }
1110 }
1111 if (p->flags & CONF_MINMAX_DEF)
1112 {
1113 if (!((p->flags & CONF_LIMIT_DEF)))
1114 flags |= CONF_MINMAX;
1115 listflags &= ~ASTCONF_system;
1116 }
1117 predef:
1118 if (look->standard == CONF_AST)
1119 {
1120 if (streq(p->name, "VERSION"))
1121 {
1122 v = ast.version;
1123 break;
1124 }
1125 }
1126 if (flags & CONF_MINMAX)
1127 {
1128 if ((p->flags & CONF_MINMAX_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_MM)))
1129 {
1130 v = p->minmax.number;
1131 s = p->minmax.string;
1132 break;
1133 }
1134 }
1135 else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
1136 {
1137 v = p->limit.number;
1138 s = p->limit.string;
1139 break;
1140 }
1141 flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1142 v = -1;
1143 errno = EINVAL;
1144 defined = 0;
1145 break;
1146 }
1147 if (!defined)
1148 {
1149 if (!errno)
1150 {
1151 if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
1152 flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1153 }
1154 else if (flags & CONF_PREFIXED)
1155 flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1156 else if (errno != EINVAL || !i)
1157 {
1158 if (!sp)
1159 {
1160 if (conferror)
1161 {
1162 if (call)
1163 (*conferror)(&state, &state, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
1164 else if (!(listflags & ASTCONF_system))
1165 (*conferror)(&state, &state, 2, "%s: unknown name", p->name);
1166 }
1167 goto bad;
1168 }
1169 else
1170 {
1171 flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1172 flags |= CONF_ERROR;
1173 }
1174 }
1175 }
1176 errno = olderrno;
1177 if ((listflags & ASTCONF_defined) && !(flags & (CONF_LIMIT_DEF|CONF_MINMAX_DEF)))
1178 goto bad;
1179 if ((drop = !sp) && !(sp = sfstropen()))
1180 goto bad;
1181 if (listflags & ASTCONF_table)
1182 {
1183 f = flg;
1184 if (p->flags & CONF_DEFER_CALL)
1185 *f++ = 'C';
1186 if (p->flags & CONF_DEFER_MM)
1187 *f++ = 'D';
1188 if (p->flags & CONF_FEATURE)
1189 *f++ = 'F';
1190 if (p->flags & CONF_LIMIT)
1191 *f++ = 'L';
1192 if (p->flags & CONF_MINMAX)
1193 *f++ = 'M';
1194 if (p->flags & CONF_NOSECTION)
1195 *f++ = 'N';
1196 if (p->flags & CONF_PREFIXED)
1197 *f++ = 'P';
1198 if (p->flags & CONF_STANDARD)
1199 *f++ = 'S';
1200 if (p->flags & CONF_UNDERSCORE)
1201 *f++ = 'U';
1202 if (p->flags & CONF_NOUNDERSCORE)
1203 *f++ = 'V';
1204 if (p->flags & CONF_PREFIX_ONLY)
1205 *f++ = 'W';
1206 if (f == flg)
1207 *f++ = 'X';
1208 *f = 0;
1209 sfprintf(sp, "%*s %*s %d %2s %4d %6s ", sizeof(p->name), p->name, sizeof(prefix[p->standard].name), prefix[p->standard].name, p->section, prefix[p->call + CONF_call].name, p->op, flg);
1210 if (p->flags & CONF_LIMIT_DEF)
1211 {
1212 if (p->limit.string)
1213 sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
1214 else
1215 sfprintf(sp, "L[%I*d] ", sizeof(p->limit.number), p->limit.number);
1216 }
1217 if (p->flags & CONF_MINMAX_DEF)
1218 {
1219 if (p->minmax.string)
1220 sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
1221 else
1222 sfprintf(sp, "M[%I*d] ", sizeof(p->minmax.number), p->minmax.number);
1223 }
1224 if (flags & CONF_ERROR)
1225 sfprintf(sp, "error");
1226 else if (defined)
1227 {
1228 if (s)
1229 sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1230 else if (v != -1)
1231 sfprintf(sp, "%I*d", sizeof(v), v);
1232 else
1233 sfprintf(sp, "%I*u", sizeof(v), v);
1234 }
1235 sfprintf(sp, "\n");
1236 }
1237 else
1238 {
1239 if (!(flags & CONF_PREFIXED) || (listflags & ASTCONF_base))
1240 {
1241 if (!name)
1242 {
1243 if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
1244 {
1245 if ((p->flags & CONF_UNDERSCORE) && !(listflags & ASTCONF_base))
1246 sfprintf(sp, "_");
1247 sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1248 if (p->section > 1)
1249 sfprintf(sp, "%d", p->section);
1250 sfprintf(sp, "_");
1251 }
1252 sfprintf(sp, "%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1253 }
1254 if (flags & CONF_ERROR)
1255 sfprintf(sp, "error");
1256 else if (defined)
1257 {
1258 if (s)
1259 sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1260 else if (v != -1)
1261 sfprintf(sp, "%I*d", sizeof(v), v);
1262 else
1263 sfprintf(sp, "%I*u", sizeof(v), v);
1264 }
1265 else
1266 sfprintf(sp, "undefined");
1267 if (!name)
1268 sfprintf(sp, "\n");
1269 }
1270 if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
1271 {
1272 if (p->flags & CONF_UNDERSCORE)
1273 sfprintf(sp, "_");
1274 sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1275 if (p->section > 1)
1276 sfprintf(sp, "%d", p->section);
1277 sfprintf(sp, "_%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1278 if (v != -1)
1279 sfprintf(sp, "%I*d", sizeof(v), v);
1280 else if (defined)
1281 sfprintf(sp, "%I*u", sizeof(v), v);
1282 else
1283 sfprintf(sp, "undefined");
1284 sfprintf(sp, "\n");
1285 }
1286 }
1287 if (drop)
1288 {
1289 if (call = sfstruse(sp))
1290 call = buffer(call);
1291 else
1292 call = "[ out of space ]";
1293 sfclose(sp);
1294 return call;
1295 }
1296 bad:
1297 return (listflags & ASTCONF_error) ? (char*)0 : null;
1298 }
1299
1300 /*
1301 * return read stream to native getconf utility
1302 */
1303
1304 static Sfio_t*
1305 nativeconf(Proc_t** pp, const char* operand)
1306 {
1307 #ifdef _pth_getconf
1308 Sfio_t* sp;
1309 char* cmd[3];
1310 long ops[2];
1311
1312 #if DEBUG_astconf
1313 error(-2, "astconf defer %s %s", _pth_getconf, operand);
1314 #endif
1315 cmd[0] = (char*)state.id;
1316 cmd[1] = (char*)operand;
1317 cmd[2] = 0;
1318 ops[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY,0), 2, PROC_FD_CHILD);
1319 ops[1] = 0;
1320 if (*pp = procopen(_pth_getconf, cmd, environ, ops, PROC_READ))
1321 {
1322 if (sp = sfnew(NiL, NiL, SF_UNBOUND, (*pp)->rfd, SF_READ))
1323 {
1324 sfdisc(sp, SF_POPDISC);
1325 return sp;
1326 }
1327 procclose(*pp);
1328 }
1329 #endif
1330 return 0;
1331 }
1332
1333 /*
1334 * value==0 gets value for name
1335 * value!=0 sets value for name and returns previous value
1336 * path==0 implies path=="/"
1337 *
1338 * settable return values are in permanent store
1339 * non-settable return values copied to a tmp fmtbuf() buffer
1340 *
1341 * if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
1342 * our_way();
1343 *
1344 * universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
1345 * astgetconf("UNIVERSE", NiL, universe, 0, 0);
1346 *
1347 * if (flags&ASTCONF_error)!=0 then error return value is 0
1348 * otherwise 0 not returned
1349 */
1350
1351 #define ALT 16
1352
1353 char*
1354 astgetconf(const char* name, const char* path, const char* value, int flags, Error_f conferror)
1355 {
1356 register char* s;
1357 int n;
1358 Lookup_t look;
1359 Sfio_t* tmp;
1360
1361 #if __OBSOLETE__ < 20080101
1362 if (pointerof(flags) == (void*)errorf)
1363 {
1364 conferror = errorf;
1365 flags = ASTCONF_error;
1366 }
1367 else if (conferror && conferror != errorf)
1368 conferror = 0;
1369 #endif
1370 if (!name)
1371 {
1372 if (path)
1373 return null;
1374 if (!(name = value))
1375 {
1376 if (state.data)
1377 {
1378 Ast_confdisc_f notify;
1379
1380 #if _HUH20000515 /* doesn't work for shell builtins */
1381 free(state.data - state.prefix);
1382 #endif
1383 state.data = 0;
1384 notify = state.notify;
1385 state.notify = 0;
1386 INITIALIZE();
1387 state.notify = notify;
1388 }
1389 return null;
1390 }
1391 value = 0;
1392 }
1393 INITIALIZE();
1394 if (!path)
1395 path = root;
1396 if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
1397 return s;
1398 if (lookup(&look, name, flags))
1399 {
1400 if (value)
1401 {
1402 ro:
1403 errno = EINVAL;
1404 if (conferror)
1405 (*conferror)(&state, &state, 2, "%s: cannot set value", name);
1406 return (flags & ASTCONF_error) ? (char*)0 : null;
1407 }
1408 return print(NiL, &look, name, path, flags, conferror);
1409 }
1410 if ((n = strlen(name)) > 3 && n < (ALT + 3))
1411 {
1412 if (streq(name + n - 3, "DEV"))
1413 {
1414 if (tmp = sfstropen())
1415 {
1416 sfprintf(tmp, "/dev/");
1417 for (s = (char*)name; s < (char*)name + n - 3; s++)
1418 sfputc(tmp, isupper(*s) ? tolower(*s) : *s);
1419 if ((s = sfstruse(tmp)) && !access(s, F_OK))
1420 {
1421 if (value)
1422 goto ro;
1423 s = buffer(s);
1424 sfclose(tmp);
1425 return s;
1426 }
1427 sfclose(tmp);
1428 }
1429 }
1430 else if (streq(name + n - 3, "DIR"))
1431 {
1432 Lookup_t altlook;
1433 char altname[ALT];
1434
1435 static const char* dirs[] = { "/usr/lib", "/usr", null };
1436
1437 strcpy(altname, name);
1438 altname[n - 3] = 0;
1439 if (lookup(&altlook, altname, flags))
1440 {
1441 if (value)
1442 {
1443 errno = EINVAL;
1444 if (conferror)
1445 (*conferror)(&state, &state, 2, "%s: cannot set value", altname);
1446 return (flags & ASTCONF_error) ? (char*)0 : null;
1447 }
1448 return print(NiL, &altlook, altname, path, flags, conferror);
1449 }
1450 for (s = altname; *s; s++)
1451 if (isupper(*s))
1452 *s = tolower(*s);
1453 if (tmp = sfstropen())
1454 {
1455 for (n = 0; n < elementsof(dirs); n++)
1456 {
1457 sfprintf(tmp, "%s/%s/.", dirs[n], altname);
1458 if ((s = sfstruse(tmp)) && !access(s, F_OK))
1459 {
1460 if (value)
1461 goto ro;
1462 s = buffer(s);
1463 sfclose(tmp);
1464 return s;
1465 }
1466 }
1467 sfclose(tmp);
1468 }
1469 }
1470 }
1471 if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(look.name, path, value, flags, conferror)))
1472 return s;
1473 errno = EINVAL;
1474 if (conferror && !(flags & ASTCONF_system))
1475 (*conferror)(&state, &state, 2, "%s: unknown name", name);
1476 return (flags & ASTCONF_error) ? (char*)0 : null;
1477 }
1478
1479 /*
1480 * astconf() never returns 0
1481 */
1482
1483 char*
1484 astconf(const char* name, const char* path, const char* value)
1485 {
1486 return astgetconf(name, path, value, 0, 0);
1487 }
1488
1489 /*
1490 * set discipline function to be called when features change
1491 * old discipline function returned
1492 */
1493
1494 Ast_confdisc_f
1495 astconfdisc(Ast_confdisc_f new_notify)
1496 {
1497 Ast_confdisc_f old_notify;
1498
1499 INITIALIZE();
1500 old_notify = state.notify;
1501 state.notify = new_notify;
1502 return old_notify;
1503 }
1504
1505 /*
1506 * list all name=value entries on sp
1507 * path==0 implies path=="/"
1508 */
1509
1510 void
1511 astconflist(Sfio_t* sp, const char* path, int flags, const char* pattern)
1512 {
1513 char* s;
1514 char* f;
1515 char* call;
1516 Feature_t* fp;
1517 Lookup_t look;
1518 regex_t re;
1519 regdisc_t redisc;
1520 int olderrno;
1521 char flg[8];
1522 #ifdef _pth_getconf_a
1523 Proc_t* proc;
1524 Sfio_t* pp;
1525 #endif
1526
1527 INITIALIZE();
1528 if (!path)
1529 path = root;
1530 else if (access(path, F_OK))
1531 {
1532 errorf(&state, &state, 2, "%s: not found", path);
1533 return;
1534 }
1535 olderrno = errno;
1536 look.flags = 0;
1537 if (!(flags & (ASTCONF_read|ASTCONF_write|ASTCONF_parse)))
1538 flags |= ASTCONF_read|ASTCONF_write;
1539 else if (flags & ASTCONF_parse)
1540 flags |= ASTCONF_write;
1541 if (!(flags & (ASTCONF_matchcall|ASTCONF_matchname|ASTCONF_matchstandard)))
1542 pattern = 0;
1543 if (pattern)
1544 {
1545 memset(&redisc, 0, sizeof(redisc));
1546 redisc.re_version = REG_VERSION;
1547 redisc.re_errorf = (regerror_t)errorf;
1548 re.re_disc = &redisc;
1549 if (regcomp(&re, pattern, REG_DISCIPLINE|REG_EXTENDED|REG_LENIENT|REG_NULL))
1550 return;
1551 }
1552 if (flags & ASTCONF_read)
1553 {
1554 for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
1555 {
1556 if (pattern)
1557 {
1558 if (flags & ASTCONF_matchcall)
1559 {
1560 if (regexec(&re, prefix[look.conf->call + CONF_call].name, 0, NiL, 0))
1561 continue;
1562 }
1563 else if (flags & ASTCONF_matchname)
1564 {
1565 if (regexec(&re, look.conf->name, 0, NiL, 0))
1566 continue;
1567 }
1568 else if (flags & ASTCONF_matchstandard)
1569 {
1570 if (regexec(&re, prefix[look.conf->standard].name, 0, NiL, 0))
1571 continue;
1572 }
1573 }
1574 print(sp, &look, NiL, path, flags, errorf);
1575 }
1576 #ifdef _pth_getconf_a
1577 if (pp = nativeconf(&proc, _pth_getconf_a))
1578 {
1579 call = "GC";
1580 while (f = sfgetr(pp, '\n', 1))
1581 {
1582 for (s = f; *s && *s != '=' && *s != ':' && !isspace(*s); s++);
1583 if (*s)
1584 for (*s++ = 0; isspace(*s); s++);
1585 if (!lookup(&look, f, flags))
1586 {
1587 if (flags & ASTCONF_table)
1588 {
1589 if (look.standard < 0)
1590 look.standard = 0;
1591 if (look.section < 1)
1592 look.section = 1;
1593 sfprintf(sp, "%*s %*s %d %2s %4d %5s %s\n", sizeof(conf[0].name), f, sizeof(prefix[look.standard].name), prefix[look.standard].name, look.section, call, 0, "N", s);
1594 }
1595 else if (flags & ASTCONF_parse)
1596 sfprintf(sp, "%s %s - %s\n", state.id, f, s);
1597 else
1598 sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1599 }
1600 }
1601 sfclose(pp);
1602 procclose(proc);
1603 }
1604 #endif
1605 }
1606 if (flags & ASTCONF_write)
1607 {
1608 call = "AC";
1609 for (fp = state.features; fp; fp = fp->next)
1610 {
1611 if (pattern)
1612 {
1613 if (flags & ASTCONF_matchcall)
1614 {
1615 if (regexec(&re, call, 0, NiL, 0))
1616 continue;
1617 }
1618 else if (flags & ASTCONF_matchname)
1619 {
1620 if (regexec(&re, fp->name, 0, NiL, 0))
1621 continue;
1622 }
1623 else if (flags & ASTCONF_matchstandard)
1624 {
1625 if (regexec(&re, prefix[fp->standard].name, 0, NiL, 0))
1626 continue;
1627 }
1628 }
1629 if (!(s = feature(fp->name, path, NiL, 0, 0)) || !*s)
1630 s = "0";
1631 if (flags & ASTCONF_table)
1632 {
1633 f = flg;
1634 if (fp->flags & CONF_ALLOC)
1635 *f++ = 'A';
1636 if (fp->flags & CONF_READONLY)
1637 *f++ = 'R';
1638 if (f == flg)
1639 *f++ = 'X';
1640 *f = 0;
1641 sfprintf(sp, "%*s %*s %d %2s %4d %5s %s\n", sizeof(conf[0].name), fp->name, sizeof(prefix[fp->standard].name), prefix[fp->standard].name, 1, call, 0, flg, s);
1642 }
1643 else if (flags & ASTCONF_parse)
1644 sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
1645 else
1646 sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1647 }
1648 }
1649 if (pattern)
1650 regfree(&re);
1651 errno = olderrno;
1652 }
1653