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