1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
25 * string interface to confstr(),pathconf(),sysconf(),sysinfo()
26 * extended to allow some features to be set per-process
29 static const char id
[] = "\n@(#)$Id: getconf (AT&T Research) 2009-07-02 $\0\n";
41 #include "FEATURE/libpath"
44 #define DEBUG_astconf 0
49 #define ASTCONF_system 0
55 # define _lib_sysinfo 1
56 # define sysinfo(a,b,c) systeminfo(a,b,c)
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)
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)
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"))
82 #if MAXVAL <= UNIV_SIZE
84 #define MAXVAL (UNIV_SIZE+1)
88 #define _UNIV_DEFAULT "att"
92 static char root
[2] = "/";
94 typedef struct Feature_s
96 struct Feature_s
*next
;
117 static Feature_t dynamic
[] =
119 #define OP_conformance 0
121 &dynamic
[OP_conformance
+1],
133 &dynamic
[OP_fs_3d
+1],
145 &dynamic
[OP_getconf
+1],
159 #define OP_hosttype 3
161 &dynamic
[OP_hosttype
+1],
173 &dynamic
[OP_libpath
+1],
187 #define OP_libprefix 5
189 &dynamic
[OP_libprefix
+1],
191 #ifdef CONF_LIBPREFIX
203 #define OP_libsuffix 6
205 &dynamic
[OP_libsuffix
+1],
207 #ifdef CONF_LIBSUFFIX
219 #define OP_path_attributes 7
221 &dynamic
[OP_path_attributes
+1],
235 #define OP_path_resolve 8
237 &dynamic
[OP_path_resolve
+1],
247 #define OP_universe 9
273 /* default initialization from here down */
283 Ast_confdisc_f notify
;
287 static State_t state
= { "getconf", "_AST_FEATURES", dynamic
, -1 };
289 static char* feature(const char*, const char*, const char*, unsigned int, Error_f
);
292 * return fmtbuf() copy of s
298 return strcpy(fmtbuf(strlen(s
) + 1), s
);
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
309 synthesize(register Feature_t
* fp
, const char* path
, const char* value
)
319 error(-2, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp
->name
, path
, value
, fp
, state
.synthesizing
? " SYNTHESIZING" : "");
321 if (state
.synthesizing
)
329 state
.prefix
= strlen(state
.name
) + 1;
330 n
= state
.prefix
+ 3 * MAXVAL
;
331 if (s
= getenv(state
.name
))
334 if (!(state
.data
= newof(0, char, n
, 0)))
336 state
.last
= state
.data
+ n
- 1;
337 strcpy(state
.data
, state
.name
);
338 state
.data
+= state
.prefix
- 1;
341 strcpy(state
.data
, s
);
343 state
.synthesizing
= 1;
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
++);
353 for (ve
= v
; *ve
&& !isspace(*ve
); ve
++);
360 feature(s
, d
, v
, 0, 0);
367 state
.synthesizing
= 0;
387 if (strneq(d
, s
, n
) && isspace(d
[n
]))
391 for (d
+= n
+ 1; *d
&& !isspace(*d
); d
++);
392 for (; isspace(*d
); d
++);
393 for (s
= d
; *s
&& !isspace(*s
); s
++);
395 value
= (const char*)d
;
398 for (s
= p
= d
+ n
+ 1; *s
&& !isspace(*s
); s
++);
399 for (; isspace(*s
); s
++);
400 for (v
= s
; *s
&& !isspace(*s
); s
++);
402 if ((!path
|| *path
== *p
&& strlen(path
) == (v
- p
- 1) && !memcmp(path
, p
, v
- p
- 1)) && strneq(v
, value
, n
))
404 for (; isspace(*s
); s
++);
406 for (; *d
= *s
++; d
++);
407 else if (d
!= state
.data
)
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
++);
421 if (fp
->flags
& CONF_ALLOC
)
430 if (!path
|| !path
[0] || path
[0] == '/' && !path
[1])
432 n
+= strlen(path
) + strlen(value
) + 3;
433 if (d
+ n
>= state
.last
)
439 state
.data
-= state
.prefix
;
440 c
= n
+ state
.last
- state
.data
+ 3 * MAXVAL
;
442 if (!(state
.data
= newof(state
.data
, char, c
, 0)))
444 state
.last
= state
.data
+ c
- 1;
445 state
.data
+= state
.prefix
;
450 for (s
= (char*)fp
->name
; *d
= *s
++; d
++);
452 for (s
= (char*)path
; *d
= *s
++; d
++);
454 for (s
= (char*)value
; *d
= *s
++; d
++);
456 error(-3, "astconf synthesize %s", state
.data
- state
.prefix
);
458 setenviron(state
.data
- state
.prefix
);
460 (*state
.notify
)(NiL
, NiL
, state
.data
- state
.prefix
);
461 n
= s
- (char*)value
- 1;
463 if (!(fp
->flags
& CONF_ALLOC
))
465 if (n
== 1 && (*value
== '0' || *value
== '-'))
467 if (!(fp
->value
= newof(fp
->value
, char, n
, 1)))
471 fp
->flags
|= CONF_ALLOC
;
472 memcpy(fp
->value
, value
, n
);
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
486 initialize(register Feature_t
* fp
, const char* path
, const char* command
, const char* succeed
, const char* fail
)
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" : "");
497 ok
= getenv("POSIXLY_CORRECT") != 0;
502 case OP_path_attributes
:
505 case OP_path_resolve
:
506 ok
= fs3d(FS3D_TEST
);
509 ok
= streq(_UNIV_DEFAULT
, DEFAULT(OP_universe
));
512 if (p
= getenv("PATH"))
515 register char* d
= p
;
519 error(-2, "astconf initialize name=%s ok=%d PATH=%s", fp
->name
, ok
, p
);
521 if (tmp
= sfstropen())
530 if (command
&& (fp
->op
!= OP_universe
|| !ok
))
536 sfputr(tmp
, command
, 0);
537 if ((d
= sfstruse(tmp
)) && !eaccess(d
, X_OK
))
540 if (fp
->op
!= OP_universe
)
552 if (fp
->op
== OP_universe
)
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')
558 for (p
+= 3; *p
== '/'; p
++);
559 if (!*p
|| *p
== ':')
564 if (fp
->op
== OP_universe
)
566 if (strneq(p
, "xpg", 3) || strneq(p
, "5bin", 4))
571 if (strneq(p
, "bsd", 3) || strneq(p
, "ucb", 3))
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
);
594 synthesize(fp
, path
, ok
? succeed
: fail
);
598 * format synthesized value
602 format(register Feature_t
* fp
, const char* path
, const char* value
, unsigned int flags
, Error_f conferror
)
604 register Feature_t
* sp
;
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" : "");
611 fp
->flags
&= ~CONF_GLOBAL
;
612 else if (fp
->flags
& CONF_GLOBAL
)
618 if (value
&& STANDARD(value
))
620 n
= state
.std
= streq(fp
->value
, fp
->std
);
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
);
624 if (!synthesize(fp
, path
, value
))
625 initialize(fp
, path
, NiL
, fp
->std
, fp
->value
);
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
);
629 if (!n
&& STANDARD(fp
->value
))
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
);
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
);
642 fp
->value
= fs3d(value
? value
[0] ? FS3D_ON
: FS3D_OFF
: FS3D_TEST
) ? "1" : null
;
648 case OP_path_attributes
:
649 #ifdef _PC_PATH_ATTRIBUTES
656 * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
659 if ((v
= pathconf(path
, _PC_PATH_ATTRIBUTES
)) == -1L)
662 e
= s
+ sizeof(fp
->value
) - 1;
663 for (n
= 'a'; n
<= 'z'; n
++)
664 if (v
& (1 << (n
- 'a')))
675 case OP_path_resolve
:
676 if (!synthesize(fp
, path
, value
))
677 initialize(fp
, path
, NiL
, "logical", DEFAULT(OP_path_resolve
));
682 if (getuniverse(fp
->value
) < 0)
683 strcpy(fp
->value
, DEFAULT(OP_universe
));
691 while (n
< univ_max
&& !streq(value
, univ_name
[n
])
696 (*conferror
)(&state
, &state
, 2, "%s: %s: universe value too large", fp
->name
, value
);
701 n
= setuniverse(n
+ 1);
705 n
= universe(value
? n
+ 1 : U_GET
);
707 if (n
<= 0 || n
>= univ_max
)
709 strcpy(fp
->value
, univ_name
[n
- 1]);
711 if (value
&& streq(path
, "="))
713 if (state
.synthesizing
)
715 if (!(fp
->flags
& CONF_ALLOC
))
718 if (!(fp
->value
= newof(fp
->value
, char, n
, 1)))
722 fp
->flags
|= CONF_ALLOC
;
723 memcpy(fp
->value
, value
, n
);
728 synthesize(fp
, path
, value
);
731 initialize(fp
, path
, "echo", DEFAULT(OP_universe
), "ucb");
737 synthesize(fp
, path
, value
);
741 if (streq(path
, "="))
742 fp
->flags
|= CONF_GLOBAL
;
747 * value==0 get feature name
748 * value!=0 set feature name
749 * 0 returned if error or not defined; otherwise previous value
753 feature(const char* name
, const char* path
, const char* value
, unsigned int flags
, Error_f conferror
)
755 register Feature_t
* fp
;
758 if (value
&& (streq(value
, "-") || streq(value
, "0")))
760 for (fp
= state
.features
; fp
&& !streq(fp
->name
, name
); fp
= fp
->next
);
762 error(-2, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name
, path
, value
, flags
, fp
, state
.synthesizing
? " SYNTHESIZING" : "");
768 if (state
.notify
&& !(*state
.notify
)(name
, path
, value
))
771 if (!(fp
= newof(0, Feature_t
, 1, n
+ 1)))
774 (*conferror
)(&state
, &state
, 2, "%s: out of space", name
);
778 fp
->name
= (const char*)fp
+ sizeof(Feature_t
);
779 strcpy((char*)fp
->name
, name
);
782 fp
->next
= state
.features
;
787 if (fp
->flags
& CONF_READONLY
)
790 (*conferror
)(&state
, &state
, 2, "%s: cannot set readonly symbol", fp
->name
);
793 if (state
.notify
&& !streq(fp
->value
, value
) && !(*state
.notify
)(name
, path
, value
))
798 return format(fp
, path
, value
, flags
, conferror
);
802 * binary search for name in conf[]
806 lookup(register Lookup_t
* look
, const char* name
, unsigned int flags
)
808 register Conf_t
* mid
= (Conf_t
*)conf
;
809 register Conf_t
* lo
= mid
;
810 register Conf_t
* hi
= mid
+ conf_elements
;
820 look
->standard
= (flags
& ASTCONF_AST
) ? CONF_AST
: -1;
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] == '_')))
830 if (look
->standard
>= 0)
832 look
->standard
= p
->standard
;
838 look
->call
= p
->call
;
840 if (name
[p
->length
] == '(' || name
[p
->length
] == '#')
843 strncpy((char*)num
.name
, name
, sizeof(num
.name
));
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
== ')')
853 name
+= p
->length
+ c
;
854 if (look
->section
< 0 && !c
&& v
)
856 look
->section
= name
[0] - '0';
862 if (look
->section
< 0)
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
);
869 c
= *((unsigned char*)name
);
872 mid
= lo
+ (hi
- lo
) / 2;
874 error(-3, "astconf lookup name=%s mid=%s", name
, mid
->name
);
876 if (!(v
= c
- *((unsigned char*)mid
->name
)) && !(v
= strcmp(name
, mid
->name
)))
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
))
886 } while (mid
-- > lo
&& streq(mid
->name
, look
->name
));
888 hi
= lo
+ conf_elements
- 1;
889 while (++mid
< hi
&& streq(mid
->name
, look
->name
))
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
))
905 if (look
->call
< 0 && look
->standard
>= 0 && (look
->section
<= 1 || (mid
->flags
& CONF_MINMAX
)))
906 look
->flags
|= CONF_MINMAX
;
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
);
915 * return a tolower'd copy of s
919 fmtlower(register const char* s
)
925 b
= t
= fmtbuf(strlen(s
) + 1);
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
943 print(Sfio_t
* sp
, register Lookup_t
* look
, const char* name
, const char* path
, int listflags
, Error_f conferror
)
945 register Conf_t
* p
= look
->conf
;
946 register unsigned int flags
= look
->flags
;
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
;
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|" : ""
984 flags
|= CONF_LIMIT_DEF
|CONF_MINMAX_DEF
;
985 if (conferror
&& name
)
987 if ((p
->flags
& CONF_PREFIX_ONLY
) && look
->standard
< 0)
989 if (!(flags
& CONF_MINMAX
) || !(p
->flags
& CONF_MINMAX
))
996 (*conferror
)(&state
, &state
, 2, "%s: path expected", name
);
1003 (*conferror
)(&state
, &state
, 2, "%s: path not expected", name
);
1009 if (p
->flags
& CONF_DEFER_CALL
)
1017 (*conferror
)(&state
, &state
, 2, "%s: path not expected", name
);
1021 if ((p
->flags
& CONF_DEFER_MM
) || !(p
->flags
& CONF_MINMAX_DEF
))
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] == '_')
1030 switch (i
= (p
->op
< 0 || (flags
& CONF_MINMAX
) && (p
->flags
& CONF_MINMAX_DEF
)) ? 0 : p
->call
)
1035 if (!(v
= confstr(p
->op
, buf
, sizeof(buf
))))
1043 buf
[sizeof(buf
) - 1] = 0;
1044 s
= (const char*)buf
;
1055 if ((v
= pathconf(path
, p
->op
)) < 0)
1064 if ((v
= sysconf(p
->op
)) < 0)
1073 if ((v
= sysinfo(p
->op
, buf
, sizeof(buf
))) >= 0)
1075 buf
[sizeof(buf
) - 1] = 0;
1076 s
= (const char*)buf
;
1092 if (p
->standard
== CONF_AST
)
1094 if (streq(p
->name
, "RELEASE") && (i
= open("/proc/version", O_RDONLY
)) >= 0)
1096 n
= read(i
, buf
, sizeof(buf
) - 1);
1098 if (n
> 0 && buf
[n
- 1] == '\n')
1100 if (n
> 0 && buf
[n
- 1] == '\r')
1111 if (p
->flags
& CONF_MINMAX_DEF
)
1113 if (!((p
->flags
& CONF_LIMIT_DEF
)))
1114 flags
|= CONF_MINMAX
;
1115 listflags
&= ~ASTCONF_system
;
1118 if (look
->standard
== CONF_AST
)
1120 if (streq(p
->name
, "VERSION"))
1126 if (flags
& CONF_MINMAX
)
1128 if ((p
->flags
& CONF_MINMAX_DEF
) && (!(listflags
& ASTCONF_system
) || !(p
->flags
& CONF_DEFER_MM
)))
1130 v
= p
->minmax
.number
;
1131 s
= p
->minmax
.string
;
1135 else if ((p
->flags
& CONF_LIMIT_DEF
) && (!(listflags
& ASTCONF_system
) || !(p
->flags
& CONF_DEFER_CALL
)))
1137 v
= p
->limit
.number
;
1138 s
= p
->limit
.string
;
1141 flags
&= ~(CONF_LIMIT_DEF
|CONF_MINMAX_DEF
);
1151 if ((p
->flags
& CONF_FEATURE
) || !(p
->flags
& (CONF_LIMIT
|CONF_MINMAX
)))
1152 flags
&= ~(CONF_LIMIT_DEF
|CONF_MINMAX_DEF
);
1154 else if (flags
& CONF_PREFIXED
)
1155 flags
&= ~(CONF_LIMIT_DEF
|CONF_MINMAX_DEF
);
1156 else if (errno
!= EINVAL
|| !i
)
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
);
1171 flags
&= ~(CONF_LIMIT_DEF
|CONF_MINMAX_DEF
);
1172 flags
|= CONF_ERROR
;
1177 if ((listflags
& ASTCONF_defined
) && !(flags
& (CONF_LIMIT_DEF
|CONF_MINMAX_DEF
)))
1179 if ((drop
= !sp
) && !(sp
= sfstropen()))
1181 if (listflags
& ASTCONF_table
)
1184 if (p
->flags
& CONF_DEFER_CALL
)
1186 if (p
->flags
& CONF_DEFER_MM
)
1188 if (p
->flags
& CONF_FEATURE
)
1190 if (p
->flags
& CONF_LIMIT
)
1192 if (p
->flags
& CONF_MINMAX
)
1194 if (p
->flags
& CONF_NOSECTION
)
1196 if (p
->flags
& CONF_PREFIXED
)
1198 if (p
->flags
& CONF_STANDARD
)
1200 if (p
->flags
& CONF_UNDERSCORE
)
1202 if (p
->flags
& CONF_NOUNDERSCORE
)
1204 if (p
->flags
& CONF_PREFIX_ONLY
)
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
)
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
);
1215 sfprintf(sp
, "L[%I*d] ", sizeof(p
->limit
.number
), p
->limit
.number
);
1217 if (p
->flags
& CONF_MINMAX_DEF
)
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
);
1222 sfprintf(sp
, "M[%I*d] ", sizeof(p
->minmax
.number
), p
->minmax
.number
);
1224 if (flags
& CONF_ERROR
)
1225 sfprintf(sp
, "error");
1229 sfprintf(sp
, "%s", (listflags
& ASTCONF_quote
) ? fmtquote(s
, "\"", "\"", strlen(s
), FMT_SHELL
) : s
);
1231 sfprintf(sp
, "%I*d", sizeof(v
), v
);
1233 sfprintf(sp
, "%I*u", sizeof(v
), v
);
1239 if (!(flags
& CONF_PREFIXED
) || (listflags
& ASTCONF_base
))
1243 if ((p
->flags
& (CONF_PREFIXED
|CONF_STRING
)) == (CONF_PREFIXED
|CONF_STRING
) && (!(listflags
& ASTCONF_base
) || p
->standard
!= CONF_POSIX
))
1245 if ((p
->flags
& CONF_UNDERSCORE
) && !(listflags
& ASTCONF_base
))
1247 sfprintf(sp
, "%s", (listflags
& ASTCONF_lower
) ? fmtlower(prefix
[p
->standard
].name
) : prefix
[p
->standard
].name
);
1249 sfprintf(sp
, "%d", p
->section
);
1252 sfprintf(sp
, "%s=", (listflags
& ASTCONF_lower
) ? fmtlower(p
->name
) : p
->name
);
1254 if (flags
& CONF_ERROR
)
1255 sfprintf(sp
, "error");
1259 sfprintf(sp
, "%s", (listflags
& ASTCONF_quote
) ? fmtquote(s
, "\"", "\"", strlen(s
), FMT_SHELL
) : s
);
1261 sfprintf(sp
, "%I*d", sizeof(v
), v
);
1263 sfprintf(sp
, "%I*u", sizeof(v
), v
);
1266 sfprintf(sp
, "undefined");
1270 if (!name
&& !(listflags
& ASTCONF_base
) && !(p
->flags
& CONF_STRING
) && (p
->flags
& (CONF_FEATURE
|CONF_MINMAX
)))
1272 if (p
->flags
& CONF_UNDERSCORE
)
1274 sfprintf(sp
, "%s", (listflags
& ASTCONF_lower
) ? fmtlower(prefix
[p
->standard
].name
) : prefix
[p
->standard
].name
);
1276 sfprintf(sp
, "%d", p
->section
);
1277 sfprintf(sp
, "_%s=", (listflags
& ASTCONF_lower
) ? fmtlower(p
->name
) : p
->name
);
1279 sfprintf(sp
, "%I*d", sizeof(v
), v
);
1281 sfprintf(sp
, "%I*u", sizeof(v
), v
);
1283 sfprintf(sp
, "undefined");
1289 if (call
= sfstruse(sp
))
1290 call
= buffer(call
);
1292 call
= "[ out of space ]";
1297 return (listflags
& ASTCONF_error
) ? (char*)0 : null
;
1301 * return read stream to native getconf utility
1305 nativeconf(Proc_t
** pp
, const char* operand
)
1313 error(-2, "astconf defer %s %s", _pth_getconf
, operand
);
1315 cmd
[0] = (char*)state
.id
;
1316 cmd
[1] = (char*)operand
;
1318 ops
[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY
,0), 2, PROC_FD_CHILD
);
1320 if (*pp
= procopen(_pth_getconf
, cmd
, environ
, ops
, PROC_READ
))
1322 if (sp
= sfnew(NiL
, NiL
, SF_UNBOUND
, (*pp
)->rfd
, SF_READ
))
1324 sfdisc(sp
, SF_POPDISC
);
1334 * value==0 gets value for name
1335 * value!=0 sets value for name and returns previous value
1336 * path==0 implies path=="/"
1338 * settable return values are in permanent store
1339 * non-settable return values copied to a tmp fmtbuf() buffer
1341 * if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
1344 * universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
1345 * astgetconf("UNIVERSE", NiL, universe, 0, 0);
1347 * if (flags&ASTCONF_error)!=0 then error return value is 0
1348 * otherwise 0 not returned
1354 astgetconf(const char* name
, const char* path
, const char* value
, int flags
, Error_f conferror
)
1361 #if __OBSOLETE__ < 20080101
1362 if (pointerof(flags
) == (void*)errorf
)
1365 flags
= ASTCONF_error
;
1367 else if (conferror
&& conferror
!= errorf
)
1374 if (!(name
= value
))
1378 Ast_confdisc_f notify
;
1380 #if _HUH20000515 /* doesn't work for shell builtins */
1381 free(state
.data
- state
.prefix
);
1384 notify
= state
.notify
;
1387 state
.notify
= notify
;
1396 if (state
.recent
&& streq(name
, state
.recent
->name
) && (s
= format(state
.recent
, path
, value
, flags
, conferror
)))
1398 if (lookup(&look
, name
, flags
))
1405 (*conferror
)(&state
, &state
, 2, "%s: cannot set value", name
);
1406 return (flags
& ASTCONF_error
) ? (char*)0 : null
;
1408 return print(NiL
, &look
, name
, path
, flags
, conferror
);
1410 if ((n
= strlen(name
)) > 3 && n
< (ALT
+ 3))
1412 if (streq(name
+ n
- 3, "DEV"))
1414 if (tmp
= sfstropen())
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
))
1430 else if (streq(name
+ n
- 3, "DIR"))
1435 static const char* dirs
[] = { "/usr/lib", "/usr", null
};
1437 strcpy(altname
, name
);
1439 if (lookup(&altlook
, altname
, flags
))
1445 (*conferror
)(&state
, &state
, 2, "%s: cannot set value", altname
);
1446 return (flags
& ASTCONF_error
) ? (char*)0 : null
;
1448 return print(NiL
, &altlook
, altname
, path
, flags
, conferror
);
1450 for (s
= altname
; *s
; s
++)
1453 if (tmp
= sfstropen())
1455 for (n
= 0; n
< elementsof(dirs
); n
++)
1457 sfprintf(tmp
, "%s/%s/.", dirs
[n
], altname
);
1458 if ((s
= sfstruse(tmp
)) && !access(s
, F_OK
))
1471 if ((look
.standard
< 0 || look
.standard
== CONF_AST
) && look
.call
<= 0 && look
.section
<= 1 && (s
= feature(look
.name
, path
, value
, flags
, conferror
)))
1474 if (conferror
&& !(flags
& ASTCONF_system
))
1475 (*conferror
)(&state
, &state
, 2, "%s: unknown name", name
);
1476 return (flags
& ASTCONF_error
) ? (char*)0 : null
;
1480 * astconf() never returns 0
1484 astconf(const char* name
, const char* path
, const char* value
)
1486 return astgetconf(name
, path
, value
, 0, 0);
1490 * set discipline function to be called when features change
1491 * old discipline function returned
1495 astconfdisc(Ast_confdisc_f new_notify
)
1497 Ast_confdisc_f old_notify
;
1500 old_notify
= state
.notify
;
1501 state
.notify
= new_notify
;
1506 * list all name=value entries on sp
1507 * path==0 implies path=="/"
1511 astconflist(Sfio_t
* sp
, const char* path
, int flags
, const char* pattern
)
1522 #ifdef _pth_getconf_a
1530 else if (access(path
, F_OK
))
1532 errorf(&state
, &state
, 2, "%s: not found", path
);
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
)))
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
))
1552 if (flags
& ASTCONF_read
)
1554 for (look
.conf
= (Conf_t
*)conf
; look
.conf
< (Conf_t
*)&conf
[conf_elements
]; look
.conf
++)
1558 if (flags
& ASTCONF_matchcall
)
1560 if (regexec(&re
, prefix
[look
.conf
->call
+ CONF_call
].name
, 0, NiL
, 0))
1563 else if (flags
& ASTCONF_matchname
)
1565 if (regexec(&re
, look
.conf
->name
, 0, NiL
, 0))
1568 else if (flags
& ASTCONF_matchstandard
)
1570 if (regexec(&re
, prefix
[look
.conf
->standard
].name
, 0, NiL
, 0))
1574 print(sp
, &look
, NiL
, path
, flags
, errorf
);
1576 #ifdef _pth_getconf_a
1577 if (pp
= nativeconf(&proc
, _pth_getconf_a
))
1580 while (f
= sfgetr(pp
, '\n', 1))
1582 for (s
= f
; *s
&& *s
!= '=' && *s
!= ':' && !isspace(*s
); s
++);
1584 for (*s
++ = 0; isspace(*s
); s
++);
1585 if (!lookup(&look
, f
, flags
))
1587 if (flags
& ASTCONF_table
)
1589 if (look
.standard
< 0)
1591 if (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
);
1595 else if (flags
& ASTCONF_parse
)
1596 sfprintf(sp
, "%s %s - %s\n", state
.id
, f
, s
);
1598 sfprintf(sp
, "%s=%s\n", f
, (flags
& ASTCONF_quote
) ? fmtquote(s
, "\"", "\"", strlen(s
), FMT_SHELL
) : s
);
1606 if (flags
& ASTCONF_write
)
1609 for (fp
= state
.features
; fp
; fp
= fp
->next
)
1613 if (flags
& ASTCONF_matchcall
)
1615 if (regexec(&re
, call
, 0, NiL
, 0))
1618 else if (flags
& ASTCONF_matchname
)
1620 if (regexec(&re
, fp
->name
, 0, NiL
, 0))
1623 else if (flags
& ASTCONF_matchstandard
)
1625 if (regexec(&re
, prefix
[fp
->standard
].name
, 0, NiL
, 0))
1629 if (!(s
= feature(fp
->name
, path
, NiL
, 0, 0)) || !*s
)
1631 if (flags
& ASTCONF_table
)
1634 if (fp
->flags
& CONF_ALLOC
)
1636 if (fp
->flags
& CONF_READONLY
)
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
);
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
));
1646 sfprintf(sp
, "%s=%s\n", (flags
& ASTCONF_lower
) ? fmtlower(fp
->name
) : fp
->name
, (flags
& ASTCONF_quote
) ? fmtquote(s
, "\"", "\"", strlen(s
), FMT_SHELL
) : s
);