xref: /onnv-gate/usr/src/lib/libast/common/port/astconf.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * string interface to confstr(),pathconf(),sysconf(),sysinfo()
264887Schin  * extended to allow some features to be set per-process
274887Schin  */
284887Schin 
2910898Sroland.mainz@nrubsig.org static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2009-07-02 $\0\n";
304887Schin 
314887Schin #include "univlib.h"
324887Schin 
334887Schin #include <ast.h>
344887Schin #include <error.h>
354887Schin #include <fs3d.h>
364887Schin #include <ctype.h>
374887Schin #include <regex.h>
384887Schin #include <proc.h>
394887Schin 
404887Schin #include "conftab.h"
414887Schin #include "FEATURE/libpath"
424887Schin 
4310898Sroland.mainz@nrubsig.org #ifndef DEBUG_astconf
4410898Sroland.mainz@nrubsig.org #define DEBUG_astconf		0
4510898Sroland.mainz@nrubsig.org #endif
4610898Sroland.mainz@nrubsig.org 
474887Schin #ifndef _pth_getconf
484887Schin #undef	ASTCONF_system
494887Schin #define ASTCONF_system		0
504887Schin #endif
514887Schin 
524887Schin #if _sys_systeminfo
534887Schin # if !_lib_sysinfo
544887Schin #   if _lib_systeminfo
554887Schin #     define _lib_sysinfo	1
564887Schin #     define sysinfo(a,b,c)	systeminfo(a,b,c)
574887Schin #   else
584887Schin #     if _lib_syscall && _sys_syscall
594887Schin #       include <sys/syscall.h>
604887Schin #       if defined(SYS_systeminfo)
614887Schin #         define _lib_sysinfo	1
624887Schin #         define sysinfo(a,b,c)	syscall(SYS_systeminfo,a,b,c)
634887Schin #       endif
644887Schin #     endif
654887Schin #   endif
664887Schin # endif
674887Schin #else
684887Schin # undef	_lib_sysinfo
694887Schin #endif
704887Schin 
714887Schin #define CONF_ERROR	(CONF_USER<<0)
724887Schin #define CONF_READONLY	(CONF_USER<<1)
734887Schin #define CONF_ALLOC	(CONF_USER<<2)
748462SApril.Chin@Sun.COM #define CONF_GLOBAL	(CONF_USER<<3)
754887Schin 
7610898Sroland.mainz@nrubsig.org #define DEFAULT(o)	((state.std||!dynamic[o].ast)?dynamic[o].std:dynamic[o].ast)
774887Schin #define INITIALIZE()	do{if(!state.data)synthesize(NiL,NiL,NiL);}while(0)
7810898Sroland.mainz@nrubsig.org #define STANDARD(v)	(streq(v,"standard")||streq(v,"strict")||streq(v,"posix")||streq(v,"xopen"))
794887Schin 
804887Schin #define MAXVAL		256
814887Schin 
824887Schin #if MAXVAL <= UNIV_SIZE
834887Schin #undef	MAXVAL
844887Schin #define	MAXVAL		(UNIV_SIZE+1)
854887Schin #endif
864887Schin 
874887Schin #ifndef _UNIV_DEFAULT
884887Schin #define _UNIV_DEFAULT	"att"
894887Schin #endif
904887Schin 
914887Schin static char	null[1];
924887Schin static char	root[2] = "/";
934887Schin 
944887Schin typedef struct Feature_s
954887Schin {
964887Schin 	struct Feature_s*next;
974887Schin 	const char*	name;
984887Schin 	char*		value;
9910898Sroland.mainz@nrubsig.org 	char*		std;
10010898Sroland.mainz@nrubsig.org 	char*		ast;
1014887Schin 	short		length;
1024887Schin 	short		standard;
1038462SApril.Chin@Sun.COM 	unsigned int	flags;
1044887Schin 	short		op;
1054887Schin } Feature_t;
1064887Schin 
1074887Schin typedef struct
1084887Schin {
1094887Schin 	Conf_t*		conf;
1104887Schin 	const char*	name;
1118462SApril.Chin@Sun.COM 	unsigned int	flags;
1124887Schin 	short		call;
1134887Schin 	short		standard;
1144887Schin 	short		section;
1154887Schin } Lookup_t;
1164887Schin 
1174887Schin static Feature_t	dynamic[] =
1184887Schin {
11910898Sroland.mainz@nrubsig.org #define OP_conformance	0
1204887Schin 	{
12110898Sroland.mainz@nrubsig.org 		&dynamic[OP_conformance+1],
1224887Schin 		"CONFORMANCE",
1234887Schin 		"ast",
1244887Schin 		"standard",
12510898Sroland.mainz@nrubsig.org 		"ast",
1264887Schin 		11,
1274887Schin 		CONF_AST,
1284887Schin 		0,
1294887Schin 		OP_conformance
1304887Schin 	},
13110898Sroland.mainz@nrubsig.org #define OP_fs_3d	1
1324887Schin 	{
13310898Sroland.mainz@nrubsig.org 		&dynamic[OP_fs_3d+1],
1344887Schin 		"FS_3D",
1354887Schin 		&null[0],
1364887Schin 		"0",
13710898Sroland.mainz@nrubsig.org 		0,
1384887Schin 		5,
1394887Schin 		CONF_AST,
1404887Schin 		0,
1414887Schin 		OP_fs_3d
1424887Schin 	},
14310898Sroland.mainz@nrubsig.org #define OP_getconf	2
1444887Schin 	{
14510898Sroland.mainz@nrubsig.org 		&dynamic[OP_getconf+1],
1464887Schin 		"GETCONF",
1474887Schin #ifdef _pth_getconf
1484887Schin 		_pth_getconf,
1494887Schin #else
1504887Schin 		&null[0],
1514887Schin #endif
1524887Schin 		0,
15310898Sroland.mainz@nrubsig.org 		0,
1544887Schin 		7,
1554887Schin 		CONF_AST,
1564887Schin 		CONF_READONLY,
1574887Schin 		OP_getconf
1584887Schin 	},
15910898Sroland.mainz@nrubsig.org #define OP_hosttype	3
1604887Schin 	{
16110898Sroland.mainz@nrubsig.org 		&dynamic[OP_hosttype+1],
1624887Schin 		"HOSTTYPE",
1634887Schin 		HOSTTYPE,
1644887Schin 		0,
16510898Sroland.mainz@nrubsig.org 		0,
1664887Schin 		8,
1674887Schin 		CONF_AST,
1684887Schin 		CONF_READONLY,
1694887Schin 		OP_hosttype
1704887Schin 	},
17110898Sroland.mainz@nrubsig.org #define OP_libpath	4
1724887Schin 	{
17310898Sroland.mainz@nrubsig.org 		&dynamic[OP_libpath+1],
1744887Schin 		"LIBPATH",
1754887Schin #ifdef CONF_LIBPATH
1764887Schin 		CONF_LIBPATH,
1774887Schin #else
1784887Schin 		&null[0],
1794887Schin #endif
1804887Schin 		0,
18110898Sroland.mainz@nrubsig.org 		0,
1824887Schin 		7,
1834887Schin 		CONF_AST,
1844887Schin 		0,
1854887Schin 		OP_libpath
1864887Schin 	},
18710898Sroland.mainz@nrubsig.org #define OP_libprefix	5
1884887Schin 	{
18910898Sroland.mainz@nrubsig.org 		&dynamic[OP_libprefix+1],
1904887Schin 		"LIBPREFIX",
1914887Schin #ifdef CONF_LIBPREFIX
1924887Schin 		CONF_LIBPREFIX,
1934887Schin #else
1944887Schin 		"lib",
1954887Schin #endif
1964887Schin 		0,
19710898Sroland.mainz@nrubsig.org 		0,
1984887Schin 		9,
1994887Schin 		CONF_AST,
2004887Schin 		0,
2014887Schin 		OP_libprefix
2024887Schin 	},
20310898Sroland.mainz@nrubsig.org #define OP_libsuffix	6
2044887Schin 	{
20510898Sroland.mainz@nrubsig.org 		&dynamic[OP_libsuffix+1],
2064887Schin 		"LIBSUFFIX",
2074887Schin #ifdef CONF_LIBSUFFIX
2084887Schin 		CONF_LIBSUFFIX,
2094887Schin #else
2104887Schin 		".so",
2114887Schin #endif
2124887Schin 		0,
21310898Sroland.mainz@nrubsig.org 		0,
2144887Schin 		9,
2154887Schin 		CONF_AST,
2164887Schin 		0,
2174887Schin 		OP_libsuffix
2184887Schin 	},
21910898Sroland.mainz@nrubsig.org #define OP_path_attributes	7
2204887Schin 	{
22110898Sroland.mainz@nrubsig.org 		&dynamic[OP_path_attributes+1],
2224887Schin 		"PATH_ATTRIBUTES",
2234887Schin #if _WINIX
2244887Schin 		"c",
2254887Schin #else
2264887Schin 		&null[0],
2274887Schin #endif
2284887Schin 		&null[0],
22910898Sroland.mainz@nrubsig.org 		0,
2304887Schin 		15,
2314887Schin 		CONF_AST,
2324887Schin 		CONF_READONLY,
2334887Schin 		OP_path_attributes
2344887Schin 	},
23510898Sroland.mainz@nrubsig.org #define OP_path_resolve	8
2364887Schin 	{
23710898Sroland.mainz@nrubsig.org 		&dynamic[OP_path_resolve+1],
2384887Schin 		"PATH_RESOLVE",
2394887Schin 		&null[0],
24010898Sroland.mainz@nrubsig.org 		"physical",
2414887Schin 		"metaphysical",
2424887Schin 		12,
2434887Schin 		CONF_AST,
2444887Schin 		0,
2454887Schin 		OP_path_resolve
2464887Schin 	},
24710898Sroland.mainz@nrubsig.org #define OP_universe	9
2484887Schin 	{
2494887Schin 		0,
2504887Schin 		"UNIVERSE",
2514887Schin 		&null[0],
2524887Schin 		"att",
25310898Sroland.mainz@nrubsig.org 		0,
2544887Schin 		8,
2554887Schin 		CONF_AST,
2564887Schin 		0,
2574887Schin 		OP_universe
2584887Schin 	},
2594887Schin 	{
2604887Schin 		0
2614887Schin 	}
2624887Schin };
2634887Schin 
2644887Schin typedef struct
2654887Schin {
2664887Schin 
2674887Schin 	const char*	id;
2684887Schin 	const char*	name;
2694887Schin 	Feature_t*	features;
2704887Schin 
27110898Sroland.mainz@nrubsig.org 	int		std;
27210898Sroland.mainz@nrubsig.org 
2734887Schin 	/* default initialization from here down */
2744887Schin 
2754887Schin 	int		prefix;
2764887Schin 	int		synthesizing;
2774887Schin 
2784887Schin 	char*		data;
2794887Schin 	char*		last;
2804887Schin 
2814887Schin 	Feature_t*	recent;
2824887Schin 
2834887Schin 	Ast_confdisc_f	notify;
2844887Schin 
2854887Schin } State_t;
2864887Schin 
28710898Sroland.mainz@nrubsig.org static State_t	state = { "getconf", "_AST_FEATURES", dynamic, -1 };
2884887Schin 
2898462SApril.Chin@Sun.COM static char*	feature(const char*, const char*, const char*, unsigned int, Error_f);
2904887Schin 
2914887Schin /*
2924887Schin  * return fmtbuf() copy of s
2934887Schin  */
2944887Schin 
2954887Schin static char*
buffer(char * s)2964887Schin buffer(char* s)
2974887Schin {
2984887Schin 	return strcpy(fmtbuf(strlen(s) + 1), s);
2994887Schin }
3004887Schin 
3014887Schin /*
3024887Schin  * synthesize state for fp
3034887Schin  * fp==0 initializes from getenv(state.name)
3044887Schin  * value==0 just does lookup
3054887Schin  * otherwise state is set to value
3064887Schin  */
3074887Schin 
3084887Schin static char*
synthesize(register Feature_t * fp,const char * path,const char * value)3094887Schin synthesize(register Feature_t* fp, const char* path, const char* value)
3104887Schin {
3114887Schin 	register char*		s;
3124887Schin 	register char*		d;
3134887Schin 	register char*		v;
31410898Sroland.mainz@nrubsig.org 	register char*		p;
3154887Schin 	register int		n;
3164887Schin 
31710898Sroland.mainz@nrubsig.org #if DEBUG_astconf
3188462SApril.Chin@Sun.COM 	if (fp)
3198462SApril.Chin@Sun.COM 		error(-2, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp->name, path, value, fp, state.synthesizing ? " SYNTHESIZING" : "");
3208462SApril.Chin@Sun.COM #endif
3214887Schin 	if (state.synthesizing)
3224887Schin 		return null;
3234887Schin 	if (!state.data)
3244887Schin 	{
3254887Schin 		char*		se;
3264887Schin 		char*		de;
3274887Schin 		char*		ve;
3284887Schin 
3294887Schin 		state.prefix = strlen(state.name) + 1;
3304887Schin 		n = state.prefix + 3 * MAXVAL;
3314887Schin 		if (s = getenv(state.name))
3324887Schin 			n += strlen(s) + 1;
3334887Schin 		n = roundof(n, 32);
3344887Schin 		if (!(state.data = newof(0, char, n, 0)))
3354887Schin 			return 0;
3364887Schin 		state.last = state.data + n - 1;
3374887Schin 		strcpy(state.data, state.name);
3384887Schin 		state.data += state.prefix - 1;
3394887Schin 		*state.data++ = '=';
3404887Schin 		if (s)
3414887Schin 			strcpy(state.data, s);
3424887Schin 		ve = state.data;
3434887Schin 		state.synthesizing = 1;
3444887Schin 		for (;;)
3454887Schin 		{
3464887Schin 			for (s = ve; isspace(*s); s++);
3474887Schin 			for (d = s; *d && !isspace(*d); d++);
3484887Schin 			for (se = d; isspace(*d); d++);
3494887Schin 			for (v = d; *v && !isspace(*v); v++);
3504887Schin 			for (de = v; isspace(*v); v++);
3514887Schin 			if (!*v)
3524887Schin 				break;
3534887Schin 			for (ve = v; *ve && !isspace(*ve); ve++);
3544887Schin 			if (*ve)
3554887Schin 				*ve = 0;
3564887Schin 			else
3574887Schin 				ve = 0;
3584887Schin 			*de = 0;
3594887Schin 			*se = 0;
3604887Schin 			feature(s, d, v, 0, 0);
3614887Schin 			*se = ' ';
3624887Schin 			*de = ' ';
3634887Schin 			if (!ve)
3644887Schin 				break;
3654887Schin 			*ve++ = ' ';
3664887Schin 		}
3674887Schin 		state.synthesizing = 0;
3684887Schin 	}
3694887Schin 	if (!fp)
3704887Schin 		return state.data;
3714887Schin 	if (!state.last)
3724887Schin 	{
3734887Schin 		if (!value)
3744887Schin 			return 0;
3754887Schin 		n = strlen(value);
3764887Schin 		goto ok;
3774887Schin 	}
3784887Schin 	s = (char*)fp->name;
3794887Schin 	n = fp->length;
3804887Schin 	d = state.data;
3814887Schin 	for (;;)
3824887Schin 	{
3834887Schin 		while (isspace(*d))
3844887Schin 			d++;
3854887Schin 		if (!*d)
3864887Schin 			break;
3874887Schin 		if (strneq(d, s, n) && isspace(d[n]))
3884887Schin 		{
3894887Schin 			if (!value)
3904887Schin 			{
3914887Schin 				for (d += n + 1; *d && !isspace(*d); d++);
3924887Schin 				for (; isspace(*d); d++);
3934887Schin 				for (s = d; *s && !isspace(*s); s++);
3944887Schin 				n = s - d;
3954887Schin 				value = (const char*)d;
3964887Schin 				goto ok;
3974887Schin 			}
39810898Sroland.mainz@nrubsig.org 			for (s = p = d + n + 1; *s && !isspace(*s); s++);
3994887Schin 			for (; isspace(*s); s++);
4004887Schin 			for (v = s; *s && !isspace(*s); s++);
4014887Schin 			n = s - v;
40210898Sroland.mainz@nrubsig.org 			if ((!path || *path == *p && strlen(path) == (v - p - 1) && !memcmp(path, p, v - p - 1)) && strneq(v, value, n))
4034887Schin 				goto ok;
4044887Schin 			for (; isspace(*s); s++);
4054887Schin 			if (*s)
4064887Schin 				for (; *d = *s++; d++);
4074887Schin 			else if (d != state.data)
4084887Schin 				d--;
4094887Schin 			break;
4104887Schin 		}
4114887Schin 		for (; *d && !isspace(*d); d++);
4124887Schin 		for (; isspace(*d); d++);
4134887Schin 		for (; *d && !isspace(*d); d++);
4144887Schin 		for (; isspace(*d); d++);
4154887Schin 		for (; *d && !isspace(*d); d++);
4164887Schin 	}
4174887Schin 	if (!value)
4184887Schin 	{
4194887Schin 		if (!fp->op)
4204887Schin 		{
4214887Schin 			if (fp->flags & CONF_ALLOC)
4224887Schin 				fp->value[0] = 0;
4234887Schin 			else
4244887Schin 				fp->value = null;
4254887Schin 		}
4264887Schin 		return 0;
4274887Schin 	}
4284887Schin 	if (!value[0])
4294887Schin 		value = "0";
4304887Schin 	if (!path || !path[0] || path[0] == '/' && !path[1])
4314887Schin 		path = "-";
4324887Schin 	n += strlen(path) + strlen(value) + 3;
4334887Schin 	if (d + n >= state.last)
4344887Schin 	{
4354887Schin 		int	c;
4364887Schin 		int	i;
4374887Schin 
4384887Schin 		i = d - state.data;
4394887Schin 		state.data -= state.prefix;
4404887Schin 		c = n + state.last - state.data + 3 * MAXVAL;
4414887Schin 		c = roundof(c, 32);
4424887Schin 		if (!(state.data = newof(state.data, char, c, 0)))
4434887Schin 			return 0;
4444887Schin 		state.last = state.data + c - 1;
4454887Schin 		state.data += state.prefix;
4464887Schin 		d = state.data + i;
4474887Schin 	}
4484887Schin 	if (d != state.data)
4494887Schin 		*d++ = ' ';
4504887Schin 	for (s = (char*)fp->name; *d = *s++; d++);
4514887Schin 	*d++ = ' ';
4524887Schin 	for (s = (char*)path; *d = *s++; d++);
4534887Schin 	*d++ = ' ';
4544887Schin 	for (s = (char*)value; *d = *s++; d++);
45510898Sroland.mainz@nrubsig.org #if DEBUG_astconf
45610898Sroland.mainz@nrubsig.org 	error(-3, "astconf synthesize %s", state.data - state.prefix);
45710898Sroland.mainz@nrubsig.org #endif
4584887Schin 	setenviron(state.data - state.prefix);
4594887Schin 	if (state.notify)
4604887Schin 		(*state.notify)(NiL, NiL, state.data - state.prefix);
4614887Schin 	n = s - (char*)value - 1;
4624887Schin  ok:
4634887Schin 	if (!(fp->flags & CONF_ALLOC))
4644887Schin 		fp->value = 0;
4654887Schin 	if (n == 1 && (*value == '0' || *value == '-'))
4664887Schin 		n = 0;
4674887Schin 	if (!(fp->value = newof(fp->value, char, n, 1)))
4684887Schin 		fp->value = null;
4694887Schin 	else
4704887Schin 	{
4714887Schin 		fp->flags |= CONF_ALLOC;
4724887Schin 		memcpy(fp->value, value, n);
4734887Schin 		fp->value[n] = 0;
4744887Schin 	}
4754887Schin 	return fp->value;
4764887Schin }
4774887Schin 
4784887Schin /*
4794887Schin  * initialize the value for fp
4804887Schin  * if command!=0 then it is checked for on $PATH
4814887Schin  * synthesize(fp,path,succeed) called on success
4824887Schin  * otherwise synthesize(fp,path,fail) called
4834887Schin  */
4844887Schin 
4854887Schin static void
initialize(register Feature_t * fp,const char * path,const char * command,const char * succeed,const char * fail)4864887Schin initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
4874887Schin {
4884887Schin 	register char*	p;
4894887Schin 	register int	ok = 1;
4904887Schin 
49110898Sroland.mainz@nrubsig.org #if DEBUG_astconf
4928462SApril.Chin@Sun.COM 	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" : "");
4938462SApril.Chin@Sun.COM #endif
4944887Schin 	switch (fp->op)
4954887Schin 	{
4964887Schin 	case OP_conformance:
4974887Schin 		ok = getenv("POSIXLY_CORRECT") != 0;
4984887Schin 		break;
4994887Schin 	case OP_hosttype:
5004887Schin 		ok = 1;
5014887Schin 		break;
5024887Schin 	case OP_path_attributes:
5034887Schin 		ok = 1;
5044887Schin 		break;
5054887Schin 	case OP_path_resolve:
5064887Schin 		ok = fs3d(FS3D_TEST);
5074887Schin 		break;
5084887Schin 	case OP_universe:
50910898Sroland.mainz@nrubsig.org 		ok = streq(_UNIV_DEFAULT, DEFAULT(OP_universe));
5104887Schin 		/*FALLTHROUGH...*/
5114887Schin 	default:
5124887Schin 		if (p = getenv("PATH"))
5134887Schin 		{
5144887Schin 			register int	r = 1;
5154887Schin 			register char*	d = p;
5164887Schin 			Sfio_t*		tmp;
5174887Schin 
51810898Sroland.mainz@nrubsig.org #if DEBUG_astconf
5198462SApril.Chin@Sun.COM 			error(-2, "astconf initialize name=%s ok=%d PATH=%s", fp->name, ok, p);
5208462SApril.Chin@Sun.COM #endif
5214887Schin 			if (tmp = sfstropen())
5224887Schin 			{
5234887Schin 				for (;;)
5244887Schin 				{
5254887Schin 					switch (*p++)
5264887Schin 					{
5274887Schin 					case 0:
5284887Schin 						break;
5294887Schin 					case ':':
5304887Schin 						if (command && (fp->op != OP_universe || !ok))
5314887Schin 						{
5324887Schin 							if (r = p - d - 1)
5334887Schin 							{
5344887Schin 								sfwrite(tmp, d, r);
5354887Schin 								sfputc(tmp, '/');
5364887Schin 								sfputr(tmp, command, 0);
5374887Schin 								if ((d = sfstruse(tmp)) && !eaccess(d, X_OK))
5384887Schin 								{
5394887Schin 									ok = 1;
5404887Schin 									if (fp->op != OP_universe)
5414887Schin 										break;
5424887Schin 								}
5434887Schin 							}
5444887Schin 							d = p;
5454887Schin 						}
5464887Schin 						r = 1;
5474887Schin 						continue;
5484887Schin 					case '/':
5494887Schin 						if (r)
5504887Schin 						{
5514887Schin 							r = 0;
5524887Schin 							if (fp->op == OP_universe)
5534887Schin 							{
5548462SApril.Chin@Sun.COM 								if (p[0] == 'u' && p[1] == 's' && p[2] == 'r' && p[3] == '/')
5558462SApril.Chin@Sun.COM 									for (p += 4; *p == '/'; p++);
5568462SApril.Chin@Sun.COM 								if (p[0] == 'b' && p[1] == 'i' && p[2] == 'n')
5578462SApril.Chin@Sun.COM 								{
5588462SApril.Chin@Sun.COM 									for (p += 3; *p == '/'; p++);
5598462SApril.Chin@Sun.COM 									if (!*p || *p == ':')
5608462SApril.Chin@Sun.COM 										break;
5618462SApril.Chin@Sun.COM 								}
5624887Schin 							}
5634887Schin 						}
5644887Schin 						if (fp->op == OP_universe)
5654887Schin 						{
5668462SApril.Chin@Sun.COM 							if (strneq(p, "xpg", 3) || strneq(p, "5bin", 4))
5674887Schin 							{
5684887Schin 								ok = 1;
5694887Schin 								break;
5704887Schin 							}
5714887Schin 							if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
5724887Schin 							{
5734887Schin 								ok = 0;
5744887Schin 								break;
5754887Schin 							}
5764887Schin 						}
5774887Schin 						continue;
5784887Schin 					default:
5794887Schin 						r = 0;
5804887Schin 						continue;
5814887Schin 					}
5824887Schin 					break;
5834887Schin 				}
5844887Schin 				sfclose(tmp);
5854887Schin 			}
5864887Schin 			else
5874887Schin 				ok = 1;
5884887Schin 		}
5894887Schin 		break;
5904887Schin 	}
59110898Sroland.mainz@nrubsig.org #if DEBUG_astconf
59210898Sroland.mainz@nrubsig.org 	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);
59310898Sroland.mainz@nrubsig.org #endif
5944887Schin 	synthesize(fp, path, ok ? succeed : fail);
5954887Schin }
5964887Schin 
5974887Schin /*
5984887Schin  * format synthesized value
5994887Schin  */
6004887Schin 
6014887Schin static char*
format(register Feature_t * fp,const char * path,const char * value,unsigned int flags,Error_f conferror)6028462SApril.Chin@Sun.COM format(register Feature_t* fp, const char* path, const char* value, unsigned int flags, Error_f conferror)
6034887Schin {
6044887Schin 	register Feature_t*	sp;
6054887Schin 	register int		n;
6064887Schin 
60710898Sroland.mainz@nrubsig.org #if DEBUG_astconf
6088462SApril.Chin@Sun.COM 	error(-2, "astconf format name=%s path=%s value=%s flags=%04x fp=%p%s", fp->name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
6098462SApril.Chin@Sun.COM #endif
6108462SApril.Chin@Sun.COM 	if (value)
6118462SApril.Chin@Sun.COM 		fp->flags &= ~CONF_GLOBAL;
6128462SApril.Chin@Sun.COM 	else if (fp->flags & CONF_GLOBAL)
6138462SApril.Chin@Sun.COM 		return fp->value;
6144887Schin 	switch (fp->op)
6154887Schin 	{
6164887Schin 
6174887Schin 	case OP_conformance:
61810898Sroland.mainz@nrubsig.org 		if (value && STANDARD(value))
61910898Sroland.mainz@nrubsig.org 			value = fp->std;
62010898Sroland.mainz@nrubsig.org 		n = state.std = streq(fp->value, fp->std);
62110898Sroland.mainz@nrubsig.org #if DEBUG_astconf
62210898Sroland.mainz@nrubsig.org 		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);
62310898Sroland.mainz@nrubsig.org #endif
6244887Schin 		if (!synthesize(fp, path, value))
62510898Sroland.mainz@nrubsig.org 			initialize(fp, path, NiL, fp->std, fp->value);
62610898Sroland.mainz@nrubsig.org #if DEBUG_astconf
62710898Sroland.mainz@nrubsig.org 		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);
62810898Sroland.mainz@nrubsig.org #endif
62910898Sroland.mainz@nrubsig.org 		if (!n && STANDARD(fp->value))
63010898Sroland.mainz@nrubsig.org 		{
63110898Sroland.mainz@nrubsig.org 			state.std = 1;
6324887Schin 			for (sp = state.features; sp; sp = sp->next)
63310898Sroland.mainz@nrubsig.org 				if (sp->std && sp->op && sp->op != OP_conformance)
63410898Sroland.mainz@nrubsig.org 					astconf(sp->name, path, sp->std);
63510898Sroland.mainz@nrubsig.org 		}
63610898Sroland.mainz@nrubsig.org #if DEBUG_astconf
63710898Sroland.mainz@nrubsig.org 		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);
63810898Sroland.mainz@nrubsig.org #endif
6394887Schin 		break;
6404887Schin 
6414887Schin 	case OP_fs_3d:
6424887Schin 		fp->value = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? "1" : null;
6434887Schin 		break;
6444887Schin 
6454887Schin 	case OP_hosttype:
6464887Schin 		break;
6474887Schin 
6484887Schin 	case OP_path_attributes:
6494887Schin #ifdef _PC_PATH_ATTRIBUTES
6504887Schin 		{
6514887Schin 			register char*	s;
6524887Schin 			register char*	e;
6534887Schin 			intmax_t	v;
6544887Schin 
6554887Schin 			/*
6564887Schin 			 * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
6574887Schin 			 */
6584887Schin 
6594887Schin 			if ((v = pathconf(path, _PC_PATH_ATTRIBUTES)) == -1L)
6604887Schin 				return 0;
6614887Schin 			s = fp->value;
6624887Schin 			e = s + sizeof(fp->value) - 1;
6634887Schin 			for (n = 'a'; n <= 'z'; n++)
6644887Schin 				if (v & (1 << (n - 'a')))
6654887Schin 				{
6664887Schin 					*s++ = n;
6674887Schin 					if (s >= e)
6684887Schin 						break;
6694887Schin 				}
6704887Schin 			*s = 0;
6714887Schin 		}
6724887Schin #endif
6734887Schin 		break;
6744887Schin 
6754887Schin 	case OP_path_resolve:
6764887Schin 		if (!synthesize(fp, path, value))
67710898Sroland.mainz@nrubsig.org 			initialize(fp, path, NiL, "logical", DEFAULT(OP_path_resolve));
6784887Schin 		break;
6794887Schin 
6804887Schin 	case OP_universe:
6814887Schin #if _lib_universe
6824887Schin 		if (getuniverse(fp->value) < 0)
68310898Sroland.mainz@nrubsig.org 			strcpy(fp->value, DEFAULT(OP_universe));
6844887Schin 		if (value)
6854887Schin 			setuniverse(value);
6864887Schin #else
6874887Schin #ifdef UNIV_MAX
6884887Schin 		n = 0;
6894887Schin 		if (value)
6904887Schin 		{
6914887Schin 			while (n < univ_max && !streq(value, univ_name[n])
6924887Schin 				n++;
6934887Schin 			if (n >= univ_max)
6944887Schin 			{
6954887Schin 				if (conferror)
6964887Schin 					(*conferror)(&state, &state, 2, "%s: %s: universe value too large", fp->name, value);
6974887Schin 				return 0;
6984887Schin 			}
6994887Schin 		}
7004887Schin #ifdef ATT_UNIV
7014887Schin 		n = setuniverse(n + 1);
7024887Schin 		if (!value && n > 0)
7034887Schin 			setuniverse(n);
7044887Schin #else
7054887Schin 		n = universe(value ? n + 1 : U_GET);
7064887Schin #endif
7074887Schin 		if (n <= 0 || n >= univ_max)
7084887Schin 			n = 1;
7094887Schin 		strcpy(fp->value, univ_name[n - 1]);
7104887Schin #else
7118462SApril.Chin@Sun.COM 		if (value && streq(path, "="))
71210898Sroland.mainz@nrubsig.org 		{
71310898Sroland.mainz@nrubsig.org 			if (state.synthesizing)
71410898Sroland.mainz@nrubsig.org 			{
71510898Sroland.mainz@nrubsig.org 				if (!(fp->flags & CONF_ALLOC))
71610898Sroland.mainz@nrubsig.org 					fp->value = 0;
71710898Sroland.mainz@nrubsig.org 				n = strlen(value);
71810898Sroland.mainz@nrubsig.org 				if (!(fp->value = newof(fp->value, char, n, 1)))
71910898Sroland.mainz@nrubsig.org 					fp->value = null;
72010898Sroland.mainz@nrubsig.org 				else
72110898Sroland.mainz@nrubsig.org 				{
72210898Sroland.mainz@nrubsig.org 					fp->flags |= CONF_ALLOC;
72310898Sroland.mainz@nrubsig.org 					memcpy(fp->value, value, n);
72410898Sroland.mainz@nrubsig.org 					fp->value[n] = 0;
72510898Sroland.mainz@nrubsig.org 				}
72610898Sroland.mainz@nrubsig.org 			}
72710898Sroland.mainz@nrubsig.org 			else
72810898Sroland.mainz@nrubsig.org 				synthesize(fp, path, value);
72910898Sroland.mainz@nrubsig.org 		}
7308462SApril.Chin@Sun.COM 		else
73110898Sroland.mainz@nrubsig.org 			initialize(fp, path, "echo", DEFAULT(OP_universe), "ucb");
7324887Schin #endif
7334887Schin #endif
7344887Schin 		break;
7354887Schin 
7364887Schin 	default:
7374887Schin 		synthesize(fp, path, value);
7384887Schin 		break;
7394887Schin 
7404887Schin 	}
7418462SApril.Chin@Sun.COM 	if (streq(path, "="))
7428462SApril.Chin@Sun.COM 		fp->flags |= CONF_GLOBAL;
7434887Schin 	return fp->value;
7444887Schin }
7454887Schin 
7464887Schin /*
7474887Schin  * value==0 get feature name
7484887Schin  * value!=0 set feature name
7494887Schin  * 0 returned if error or not defined; otherwise previous value
7504887Schin  */
7514887Schin 
7524887Schin static char*
7538462SApril.Chin@Sun.COM feature(const char* name, const char* path, const char* value, unsigned int flags, Error_f conferror)
7544887Schin {
7554887Schin 	register Feature_t*	fp;
7564887Schin 	register int		n;
7574887Schin 
7584887Schin 	if (value && (streq(value, "-") || streq(value, "0")))
7594887Schin 		value = null;
7604887Schin 	for (fp = state.features; fp && !streq(fp->name, name); fp = fp->next);
76110898Sroland.mainz@nrubsig.org #if DEBUG_astconf
7628462SApril.Chin@Sun.COM 	error(-2, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
7634887Schin #endif
7644887Schin 	if (!fp)
7654887Schin 	{
7664887Schin 		if (!value)
7674887Schin 			return 0;
7684887Schin 		if (state.notify && !(*state.notify)(name, path, value))
7694887Schin 			return 0;
7704887Schin 		n = strlen(name);
7714887Schin 		if (!(fp = newof(0, Feature_t, 1, n + 1)))
7724887Schin 		{
7734887Schin 			if (conferror)
7744887Schin 				(*conferror)(&state, &state, 2, "%s: out of space", name);
7754887Schin 			return 0;
7764887Schin 		}
77710898Sroland.mainz@nrubsig.org 		fp->op = -1;
7784887Schin 		fp->name = (const char*)fp + sizeof(Feature_t);
7794887Schin 		strcpy((char*)fp->name, name);
7804887Schin 		fp->length = n;
78110898Sroland.mainz@nrubsig.org 		fp->std = &null[0];
7824887Schin 		fp->next = state.features;
7834887Schin 		state.features = fp;
7844887Schin 	}
7854887Schin 	else if (value)
7864887Schin 	{
7874887Schin 		if (fp->flags & CONF_READONLY)
7884887Schin 		{
7894887Schin 			if (conferror)
7904887Schin 				(*conferror)(&state, &state, 2, "%s: cannot set readonly symbol", fp->name);
7914887Schin 			return 0;
7924887Schin 		}
7934887Schin 		if (state.notify && !streq(fp->value, value) && !(*state.notify)(name, path, value))
7944887Schin 			return 0;
7954887Schin 	}
7964887Schin 	else
7974887Schin 		state.recent = fp;
7984887Schin 	return format(fp, path, value, flags, conferror);
7994887Schin }
8004887Schin 
8014887Schin /*
8024887Schin  * binary search for name in conf[]
8034887Schin  */
8044887Schin 
8054887Schin static int
8068462SApril.Chin@Sun.COM lookup(register Lookup_t* look, const char* name, unsigned int flags)
8074887Schin {
8084887Schin 	register Conf_t*	mid = (Conf_t*)conf;
8094887Schin 	register Conf_t*	lo = mid;
8104887Schin 	register Conf_t*	hi = mid + conf_elements;
8114887Schin 	register int		v;
8124887Schin 	register int		c;
8134887Schin 	char*			e;
8144887Schin 	const Prefix_t*		p;
8154887Schin 
8164887Schin 	static Conf_t		num;
8174887Schin 
8184887Schin 	look->flags = 0;
8194887Schin 	look->call = -1;
8204887Schin 	look->standard = (flags & ASTCONF_AST) ? CONF_AST : -1;
8214887Schin 	look->section = -1;
8224887Schin 	while (*name == '_')
8234887Schin 		name++;
8244887Schin  again:
8254887Schin 	for (p = prefix; p < &prefix[prefix_elements]; p++)
8268462SApril.Chin@Sun.COM 		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] == '_')))
8274887Schin 		{
8284887Schin 			if (p->call < 0)
8294887Schin 			{
8304887Schin 				if (look->standard >= 0)
8314887Schin 					break;
8324887Schin 				look->standard = p->standard;
8334887Schin 			}
8344887Schin 			else
8354887Schin 			{
8364887Schin 				if (look->call >= 0)
8374887Schin 					break;
8384887Schin 				look->call = p->call;
8394887Schin 			}
8408462SApril.Chin@Sun.COM 			if (name[p->length] == '(' || name[p->length] == '#')
8414887Schin 			{
8424887Schin 				look->conf = &num;
8434887Schin 				strncpy((char*)num.name, name, sizeof(num.name));
8444887Schin 				num.call = p->call;
8454887Schin 				num.flags = *name == 'C' ? CONF_STRING : 0;
8464887Schin 				num.op = (short)strtol(name + p->length + 1, &e, 10);
8478462SApril.Chin@Sun.COM 				if (name[p->length] == '(' && *e == ')')
8488462SApril.Chin@Sun.COM 					e++;
8498462SApril.Chin@Sun.COM 				if (*e)
8504887Schin 					break;
8514887Schin 				return 1;
8524887Schin 			}
8534887Schin 			name += p->length + c;
8544887Schin 			if (look->section < 0 && !c && v)
8554887Schin 			{
8564887Schin 				look->section = name[0] - '0';
8574887Schin 				name += 2;
8584887Schin 			}
8594887Schin 			goto again;
8604887Schin 		}
8614887Schin #if HUH_2006_02_10
8624887Schin 	if (look->section < 0)
8634887Schin 		look->section = 1;
8644887Schin #endif
8654887Schin 	look->name = name;
86610898Sroland.mainz@nrubsig.org #if DEBUG_astconf
8674887Schin 	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);
8684887Schin #endif
8694887Schin 	c = *((unsigned char*)name);
8704887Schin 	while (lo <= hi)
8714887Schin 	{
8724887Schin 		mid = lo + (hi - lo) / 2;
87310898Sroland.mainz@nrubsig.org #if DEBUG_astconf
8744887Schin 		error(-3, "astconf lookup name=%s mid=%s", name, mid->name);
8754887Schin #endif
8764887Schin 		if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
8774887Schin 		{
8784887Schin 			hi = mid;
8794887Schin 			lo = (Conf_t*)conf;
8804887Schin 			do
8814887Schin 			{
8824887Schin 				if ((look->standard < 0 || look->standard == mid->standard) &&
8834887Schin 				    (look->section < 0 || look->section == mid->section) &&
8844887Schin 				    (look->call < 0 || look->call == mid->call))
8854887Schin 					goto found;
8864887Schin 			} while (mid-- > lo && streq(mid->name, look->name));
8874887Schin 			mid = hi;
8884887Schin 			hi = lo + conf_elements - 1;
8894887Schin 			while (++mid < hi && streq(mid->name, look->name))
8904887Schin 			{
8914887Schin 				if ((look->standard < 0 || look->standard == mid->standard) &&
8924887Schin 				    (look->section < 0 || look->section == mid->section) &&
8934887Schin 				    (look->call < 0 || look->call == mid->call))
8944887Schin 					goto found;
8954887Schin 			}
8964887Schin 			break;
8974887Schin 		}
8984887Schin 		else if (v > 0)
8994887Schin 			lo = mid + 1;
9004887Schin 		else
9014887Schin 			hi = mid - 1;
9024887Schin 	}
9034887Schin 	return 0;
9044887Schin  found:
9054887Schin 	if (look->call < 0 && look->standard >= 0 && (look->section <= 1 || (mid->flags & CONF_MINMAX)))
9064887Schin 		look->flags |= CONF_MINMAX;
9074887Schin 	look->conf = mid;
90810898Sroland.mainz@nrubsig.org #if DEBUG_astconf
9094887Schin 	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);
9104887Schin #endif
9114887Schin 	return 1;
9124887Schin }
9134887Schin 
9144887Schin /*
9154887Schin  * return a tolower'd copy of s
9164887Schin  */
9174887Schin 
9184887Schin static char*
9194887Schin fmtlower(register const char* s)
9204887Schin {
9214887Schin 	register int	c;
9224887Schin 	register char*	t;
9234887Schin 	char*		b;
9244887Schin 
9254887Schin 	b = t = fmtbuf(strlen(s) + 1);
9264887Schin 	while (c = *s++)
9274887Schin 	{
9284887Schin 		if (isupper(c))
9294887Schin 			c = tolower(c);
9304887Schin 		*t++ = c;
9314887Schin 	}
9324887Schin 	*t = 0;
9334887Schin 	return b;
9344887Schin }
9354887Schin 
9364887Schin /*
9374887Schin  * print value line for p
9384887Schin  * if !name then value prefixed by "p->name="
9394887Schin  * if (flags & CONF_MINMAX) then default minmax value used
9404887Schin  */
9414887Schin 
9424887Schin static char*
9434887Schin print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
9444887Schin {
9454887Schin 	register Conf_t*	p = look->conf;
9468462SApril.Chin@Sun.COM 	register unsigned int	flags = look->flags;
9474887Schin 	char*			call;
9484887Schin 	char*			f;
9494887Schin 	const char*		s;
9504887Schin 	int			i;
9518462SApril.Chin@Sun.COM 	int			n;
9524887Schin 	int			olderrno;
9534887Schin 	int			drop;
9544887Schin 	int			defined;
9554887Schin 	intmax_t		v;
9564887Schin 	char			buf[PATH_MAX];
9574887Schin 	char			flg[16];
9584887Schin 
9594887Schin 	if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
9604887Schin 		flags |= CONF_PREFIXED;
9614887Schin 	olderrno = errno;
9624887Schin 	errno = 0;
96310898Sroland.mainz@nrubsig.org #if DEBUG_astconf
96410898Sroland.mainz@nrubsig.org 	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"
96510898Sroland.mainz@nrubsig.org 		, name, look->name, p->name, p->standard, p->section, prefix[p->call + CONF_call].name, p->op
9664887Schin 		, (flags & CONF_FEATURE) ? "FEATURE|" : ""
9674887Schin 		, (flags & CONF_LIMIT) ? "LIMIT|" : ""
9684887Schin 		, (flags & CONF_MINMAX) ? "MINMAX|" : ""
9694887Schin 		, (flags & CONF_PREFIXED) ? "PREFIXED|" : ""
9704887Schin 		, (flags & CONF_STRING) ? "STRING|" : ""
9714887Schin 		, (p->flags & CONF_DEFER_CALL) ? "DEFER_CALL|" : ""
9724887Schin 		, (p->flags & CONF_DEFER_MM) ? "DEFER_MM|" : ""
9734887Schin 		, (p->flags & CONF_FEATURE) ? "FEATURE|" : ""
9744887Schin 		, (p->flags & CONF_LIMIT_DEF) ? "LIMIT_DEF|" : (p->flags & CONF_LIMIT) ? "LIMIT|" : ""
9754887Schin 		, (p->flags & CONF_MINMAX_DEF) ? "MINMAX_DEF|" : (p->flags & CONF_MINMAX) ? "MINMAX|" : ""
9764887Schin 		, (p->flags & CONF_NOUNDERSCORE) ? "NOUNDERSCORE|" : ""
9774887Schin 		, (p->flags & CONF_PREFIXED) ? "PREFIXED|" : ""
9784887Schin 		, (p->flags & CONF_PREFIX_ONLY) ? "PREFIX_ONLY|" : ""
9794887Schin 		, (p->flags & CONF_STANDARD) ? "STANDARD|" : ""
9804887Schin 		, (p->flags & CONF_STRING) ? "STRING|" : ""
9814887Schin 		, (p->flags & CONF_UNDERSCORE) ? "UNDERSCORE|" : ""
9824887Schin 		);
9834887Schin #endif
9844887Schin 	flags |= CONF_LIMIT_DEF|CONF_MINMAX_DEF;
9854887Schin 	if (conferror && name)
9864887Schin 	{
9874887Schin 		if ((p->flags & CONF_PREFIX_ONLY) && look->standard < 0)
9884887Schin 			goto bad;
9894887Schin 		if (!(flags & CONF_MINMAX) || !(p->flags & CONF_MINMAX))
9904887Schin 		{
9914887Schin 			switch (p->call)
9924887Schin 			{
9934887Schin 			case CONF_pathconf:
9944887Schin 				if (path == root)
9954887Schin 				{
9964887Schin 					(*conferror)(&state, &state, 2, "%s: path expected", name);
9974887Schin 					goto bad;
9984887Schin 				}
9994887Schin 				break;
10004887Schin 			default:
10014887Schin 				if (path != root)
10024887Schin 				{
10034887Schin 					(*conferror)(&state, &state, 2, "%s: path not expected", name);
10044887Schin 					goto bad;
10054887Schin 				}
10064887Schin 				break;
10074887Schin 			}
10084887Schin #ifdef _pth_getconf
10094887Schin 			if (p->flags & CONF_DEFER_CALL)
10104887Schin 				goto bad;
10114887Schin #endif
10124887Schin 		}
10134887Schin 		else
10144887Schin 		{
10154887Schin 			if (path != root)
10164887Schin 			{
10174887Schin 				(*conferror)(&state, &state, 2, "%s: path not expected", name);
10184887Schin 				goto bad;
10194887Schin 			}
10204887Schin #ifdef _pth_getconf
10214887Schin 			if ((p->flags & CONF_DEFER_MM) || !(p->flags & CONF_MINMAX_DEF))
10224887Schin 				goto bad;
10234887Schin #endif
10244887Schin 		}
10254887Schin 		if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
10264887Schin 			goto bad;
10274887Schin 	}
10284887Schin 	s = 0;
10294887Schin 	defined = 1;
10304887Schin 	switch (i = (p->op < 0 || (flags & CONF_MINMAX) && (p->flags & CONF_MINMAX_DEF)) ? 0 : p->call)
10314887Schin 	{
10324887Schin 	case CONF_confstr:
10334887Schin 		call = "confstr";
10344887Schin #if _lib_confstr
10354887Schin 		if (!(v = confstr(p->op, buf, sizeof(buf))))
10364887Schin 		{
10374887Schin 			defined = 0;
10384887Schin 			v = -1;
10394887Schin 			errno = EINVAL;
10404887Schin 		}
10414887Schin 		else if (v > 0)
10424887Schin 		{
10434887Schin 			buf[sizeof(buf) - 1] = 0;
10444887Schin 			s = (const char*)buf;
10454887Schin 		}
10464887Schin 		else
10474887Schin 			defined = 0;
10484887Schin 		break;
10494887Schin #else
10504887Schin 		goto predef;
10514887Schin #endif
10524887Schin 	case CONF_pathconf:
10534887Schin 		call = "pathconf";
10544887Schin #if _lib_pathconf
10554887Schin 		if ((v = pathconf(path, p->op)) < 0)
10564887Schin 			defined = 0;
10574887Schin 		break;
10584887Schin #else
10594887Schin 		goto predef;
10604887Schin #endif
10614887Schin 	case CONF_sysconf:
10624887Schin 		call = "sysconf";
10634887Schin #if _lib_sysconf
10644887Schin 		if ((v = sysconf(p->op)) < 0)
10654887Schin 			defined = 0;
10664887Schin 		break;
10674887Schin #else
10684887Schin 		goto predef;
10694887Schin #endif
10704887Schin 	case CONF_sysinfo:
10714887Schin 		call = "sysinfo";
10724887Schin #if _lib_sysinfo
10734887Schin 		if ((v = sysinfo(p->op, buf, sizeof(buf))) >= 0)
10744887Schin 		{
10754887Schin 			buf[sizeof(buf) - 1] = 0;
10764887Schin 			s = (const char*)buf;
10774887Schin 		}
10784887Schin 		else
10794887Schin 			defined = 0;
10804887Schin 		break;
10814887Schin #else
10824887Schin 		goto predef;
10834887Schin #endif
10844887Schin 	default:
10854887Schin 		call = "synthesis";
10864887Schin 		errno = EINVAL;
10874887Schin 		v = -1;
10884887Schin 		defined = 0;
10894887Schin 		break;
10904887Schin 	case 0:
10914887Schin 		call = 0;
10928462SApril.Chin@Sun.COM 		if (p->standard == CONF_AST)
10938462SApril.Chin@Sun.COM 		{
109410898Sroland.mainz@nrubsig.org 			if (streq(p->name, "RELEASE") && (i = open("/proc/version", O_RDONLY)) >= 0)
10958462SApril.Chin@Sun.COM 			{
10968462SApril.Chin@Sun.COM 				n = read(i, buf, sizeof(buf) - 1);
10978462SApril.Chin@Sun.COM 				close(i);
10988462SApril.Chin@Sun.COM 				if (n > 0 && buf[n - 1] == '\n')
10998462SApril.Chin@Sun.COM 					n--;
11008462SApril.Chin@Sun.COM 				if (n > 0 && buf[n - 1] == '\r')
11018462SApril.Chin@Sun.COM 					n--;
11028462SApril.Chin@Sun.COM 				buf[n] = 0;
11038462SApril.Chin@Sun.COM 				if (buf[0])
11048462SApril.Chin@Sun.COM 				{
11058462SApril.Chin@Sun.COM 					v = 0;
11068462SApril.Chin@Sun.COM 					s = buf;
11078462SApril.Chin@Sun.COM 					break;
11088462SApril.Chin@Sun.COM 				}
11098462SApril.Chin@Sun.COM 			}
11108462SApril.Chin@Sun.COM 		}
11114887Schin 		if (p->flags & CONF_MINMAX_DEF)
11124887Schin 		{
11134887Schin 			if (!((p->flags & CONF_LIMIT_DEF)))
11144887Schin 				flags |= CONF_MINMAX;
11154887Schin 			listflags &= ~ASTCONF_system;
11164887Schin 		}
11174887Schin 	predef:
11184887Schin 		if (look->standard == CONF_AST)
11194887Schin 		{
112010898Sroland.mainz@nrubsig.org 			if (streq(p->name, "VERSION"))
11214887Schin 			{
1122*12068SRoger.Faulkner@Oracle.COM 				v = ast.version;
11234887Schin 				break;
11244887Schin 			}
11254887Schin 		}
11264887Schin 		if (flags & CONF_MINMAX)
11274887Schin 		{
11284887Schin 			if ((p->flags & CONF_MINMAX_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_MM)))
11294887Schin 			{
11304887Schin 				v = p->minmax.number;
11314887Schin 				s = p->minmax.string;
11324887Schin 				break;
11334887Schin 			}
11344887Schin 		}
11354887Schin 		else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
11364887Schin 		{
11374887Schin 			v = p->limit.number;
11384887Schin 			s = p->limit.string;
11394887Schin 			break;
11404887Schin 		}
11414887Schin 		flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
11424887Schin 		v = -1;
11434887Schin 		errno = EINVAL;
11444887Schin 		defined = 0;
11454887Schin 		break;
11464887Schin 	}
11474887Schin 	if (!defined)
11484887Schin 	{
11494887Schin 		if (!errno)
11504887Schin 		{
11514887Schin 			if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
11524887Schin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
11534887Schin 		}
11544887Schin 		else if (flags & CONF_PREFIXED)
11554887Schin 			flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
11564887Schin 		else if (errno != EINVAL || !i)
11574887Schin 		{
11584887Schin 			if (!sp)
11594887Schin 			{
11604887Schin 				if (conferror)
11614887Schin 				{
11624887Schin 					if (call)
11634887Schin 						(*conferror)(&state, &state, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
11644887Schin 					else if (!(listflags & ASTCONF_system))
11654887Schin 						(*conferror)(&state, &state, 2, "%s: unknown name", p->name);
11664887Schin 				}
11674887Schin 				goto bad;
11684887Schin 			}
11694887Schin 			else
11704887Schin 			{
11714887Schin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
11724887Schin 				flags |= CONF_ERROR;
11734887Schin 			}
11744887Schin 		}
11754887Schin 	}
11764887Schin 	errno = olderrno;
11774887Schin 	if ((listflags & ASTCONF_defined) && !(flags & (CONF_LIMIT_DEF|CONF_MINMAX_DEF)))
11784887Schin 		goto bad;
11794887Schin 	if ((drop = !sp) && !(sp = sfstropen()))
11804887Schin 		goto bad;
11814887Schin 	if (listflags & ASTCONF_table)
11824887Schin 	{
11834887Schin 		f = flg;
11844887Schin 		if (p->flags & CONF_DEFER_CALL)
11854887Schin 			*f++ = 'C';
11864887Schin 		if (p->flags & CONF_DEFER_MM)
11874887Schin 			*f++ = 'D';
11884887Schin 		if (p->flags & CONF_FEATURE)
11894887Schin 			*f++ = 'F';
11904887Schin 		if (p->flags & CONF_LIMIT)
11914887Schin 			*f++ = 'L';
11924887Schin 		if (p->flags & CONF_MINMAX)
11934887Schin 			*f++ = 'M';
11944887Schin 		if (p->flags & CONF_NOSECTION)
11954887Schin 			*f++ = 'N';
11964887Schin 		if (p->flags & CONF_PREFIXED)
11974887Schin 			*f++ = 'P';
11984887Schin 		if (p->flags & CONF_STANDARD)
11994887Schin 			*f++ = 'S';
12004887Schin 		if (p->flags & CONF_UNDERSCORE)
12014887Schin 			*f++ = 'U';
12024887Schin 		if (p->flags & CONF_NOUNDERSCORE)
12034887Schin 			*f++ = 'V';
12044887Schin 		if (p->flags & CONF_PREFIX_ONLY)
12054887Schin 			*f++ = 'W';
12064887Schin 		if (f == flg)
12074887Schin 			*f++ = 'X';
12084887Schin 		*f = 0;
12094887Schin 		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);
12104887Schin 		if (p->flags & CONF_LIMIT_DEF)
12114887Schin 		{
12124887Schin 			if (p->limit.string)
12134887Schin 				sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
12144887Schin 			else
12154887Schin 				sfprintf(sp, "L[%I*d] ", sizeof(p->limit.number), p->limit.number);
12164887Schin 		}
12174887Schin 		if (p->flags & CONF_MINMAX_DEF)
12184887Schin 		{
12194887Schin 			if (p->minmax.string)
12204887Schin 				sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
12214887Schin 			else
12224887Schin 				sfprintf(sp, "M[%I*d] ", sizeof(p->minmax.number), p->minmax.number);
12234887Schin 		}
12244887Schin 		if (flags & CONF_ERROR)
12254887Schin 			sfprintf(sp, "error");
12264887Schin 		else if (defined)
12274887Schin 		{
12284887Schin 			if (s)
12294887Schin 				sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
12304887Schin 			else if (v != -1)
12314887Schin 				sfprintf(sp, "%I*d", sizeof(v), v);
12324887Schin 			else
12334887Schin 				sfprintf(sp, "%I*u", sizeof(v), v);
12344887Schin 		}
12354887Schin 		sfprintf(sp, "\n");
12364887Schin 	}
12374887Schin 	else
12384887Schin 	{
12394887Schin 		if (!(flags & CONF_PREFIXED) || (listflags & ASTCONF_base))
12404887Schin 		{
12414887Schin 			if (!name)
12424887Schin 			{
12434887Schin 				if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
12444887Schin 				{
12454887Schin 					if ((p->flags & CONF_UNDERSCORE) && !(listflags & ASTCONF_base))
12464887Schin 						sfprintf(sp, "_");
12474887Schin 					sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
12484887Schin 					if (p->section > 1)
12494887Schin 						sfprintf(sp, "%d", p->section);
12504887Schin 					sfprintf(sp, "_");
12514887Schin 				}
12524887Schin 				sfprintf(sp, "%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
12534887Schin 			}
12544887Schin 			if (flags & CONF_ERROR)
12554887Schin 				sfprintf(sp, "error");
12564887Schin 			else if (defined)
12574887Schin 			{
12584887Schin 				if (s)
12594887Schin 					sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
12604887Schin 				else if (v != -1)
12614887Schin 					sfprintf(sp, "%I*d", sizeof(v), v);
12624887Schin 				else
12634887Schin 					sfprintf(sp, "%I*u", sizeof(v), v);
12644887Schin 			}
12654887Schin 			else
12664887Schin 				sfprintf(sp, "undefined");
12674887Schin 			if (!name)
12684887Schin 				sfprintf(sp, "\n");
12694887Schin 		}
12704887Schin 		if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
12714887Schin 		{
12724887Schin 			if (p->flags & CONF_UNDERSCORE)
12734887Schin 				sfprintf(sp, "_");
12744887Schin 			sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
12754887Schin 			if (p->section > 1)
12764887Schin 				sfprintf(sp, "%d", p->section);
12774887Schin 			sfprintf(sp, "_%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
12784887Schin 			if (v != -1)
12794887Schin 				sfprintf(sp, "%I*d", sizeof(v), v);
12804887Schin 			else if (defined)
12814887Schin 				sfprintf(sp, "%I*u", sizeof(v), v);
12824887Schin 			else
12834887Schin 				sfprintf(sp, "undefined");
12844887Schin 			sfprintf(sp, "\n");
12854887Schin 		}
12864887Schin 	}
12874887Schin 	if (drop)
12884887Schin 	{
12894887Schin 		if (call = sfstruse(sp))
12904887Schin 			call = buffer(call);
12914887Schin 		else
12924887Schin 			call = "[ out of space ]";
12934887Schin 		sfclose(sp);
12944887Schin 		return call;
12954887Schin 	}
12964887Schin  bad:
12974887Schin 	return (listflags & ASTCONF_error) ? (char*)0 : null;
12984887Schin }
12994887Schin 
13004887Schin /*
13014887Schin  * return read stream to native getconf utility
13024887Schin  */
13034887Schin 
13044887Schin static Sfio_t*
13054887Schin nativeconf(Proc_t** pp, const char* operand)
13064887Schin {
13074887Schin #ifdef _pth_getconf
13084887Schin 	Sfio_t*		sp;
13094887Schin 	char*		cmd[3];
13104887Schin 	long		ops[2];
13114887Schin 
131210898Sroland.mainz@nrubsig.org #if DEBUG_astconf
13134887Schin 	error(-2, "astconf defer %s %s", _pth_getconf, operand);
13144887Schin #endif
13154887Schin 	cmd[0] = (char*)state.id;
13164887Schin 	cmd[1] = (char*)operand;
13174887Schin 	cmd[2] = 0;
13184887Schin 	ops[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY,0), 2, PROC_FD_CHILD);
13194887Schin 	ops[1] = 0;
13204887Schin 	if (*pp = procopen(_pth_getconf, cmd, environ, ops, PROC_READ))
13214887Schin 	{
13224887Schin 		if (sp = sfnew(NiL, NiL, SF_UNBOUND, (*pp)->rfd, SF_READ))
13234887Schin 		{
13244887Schin 			sfdisc(sp, SF_POPDISC);
13254887Schin 			return sp;
13264887Schin 		}
13274887Schin 		procclose(*pp);
13284887Schin 	}
13294887Schin #endif
13304887Schin 	return 0;
13314887Schin }
13324887Schin 
13334887Schin /*
13344887Schin  * value==0 gets value for name
13354887Schin  * value!=0 sets value for name and returns previous value
13364887Schin  * path==0 implies path=="/"
13374887Schin  *
13384887Schin  * settable return values are in permanent store
13394887Schin  * non-settable return values copied to a tmp fmtbuf() buffer
13404887Schin  *
13414887Schin  *	if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
13424887Schin  *		our_way();
13434887Schin  *
13444887Schin  *	universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
13454887Schin  *	astgetconf("UNIVERSE", NiL, universe, 0, 0);
13464887Schin  *
13474887Schin  * if (flags&ASTCONF_error)!=0 then error return value is 0
13484887Schin  * otherwise 0 not returned
13494887Schin  */
13504887Schin 
13514887Schin #define ALT	16
13524887Schin 
13534887Schin char*
13544887Schin astgetconf(const char* name, const char* path, const char* value, int flags, Error_f conferror)
13554887Schin {
13564887Schin 	register char*	s;
13574887Schin 	int		n;
13584887Schin 	Lookup_t	look;
13594887Schin 	Sfio_t*		tmp;
13604887Schin 
13614887Schin #if __OBSOLETE__ < 20080101
13624887Schin 	if (pointerof(flags) == (void*)errorf)
13634887Schin 	{
13644887Schin 		conferror = errorf;
13654887Schin 		flags = ASTCONF_error;
13664887Schin 	}
13674887Schin 	else if (conferror && conferror != errorf)
13684887Schin 		conferror = 0;
13694887Schin #endif
13704887Schin 	if (!name)
13714887Schin 	{
13724887Schin 		if (path)
13734887Schin 			return null;
13744887Schin 		if (!(name = value))
13754887Schin 		{
13764887Schin 			if (state.data)
13774887Schin 			{
13784887Schin 				Ast_confdisc_f	notify;
13794887Schin 
13804887Schin #if _HUH20000515 /* doesn't work for shell builtins */
13814887Schin 				free(state.data - state.prefix);
13824887Schin #endif
13834887Schin 				state.data = 0;
13844887Schin 				notify = state.notify;
13854887Schin 				state.notify = 0;
13864887Schin 				INITIALIZE();
13874887Schin 				state.notify = notify;
13884887Schin 			}
13894887Schin 			return null;
13904887Schin 		}
13914887Schin 		value = 0;
13924887Schin 	}
13934887Schin 	INITIALIZE();
13944887Schin 	if (!path)
13954887Schin 		path = root;
13964887Schin 	if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
13974887Schin 		return s;
13984887Schin 	if (lookup(&look, name, flags))
13994887Schin 	{
14004887Schin 		if (value)
14014887Schin 		{
14024887Schin 		ro:
14034887Schin 			errno = EINVAL;
14044887Schin 			if (conferror)
14054887Schin 				(*conferror)(&state, &state, 2, "%s: cannot set value", name);
14064887Schin 			return (flags & ASTCONF_error) ? (char*)0 : null;
14074887Schin 		}
14084887Schin 		return print(NiL, &look, name, path, flags, conferror);
14094887Schin 	}
14104887Schin 	if ((n = strlen(name)) > 3 && n < (ALT + 3))
14114887Schin 	{
14124887Schin 		if (streq(name + n - 3, "DEV"))
14134887Schin 		{
14144887Schin 			if (tmp = sfstropen())
14154887Schin 			{
14164887Schin 				sfprintf(tmp, "/dev/");
14174887Schin 				for (s = (char*)name; s < (char*)name + n - 3; s++)
14184887Schin 					sfputc(tmp, isupper(*s) ? tolower(*s) : *s);
14194887Schin 				if ((s = sfstruse(tmp)) && !access(s, F_OK))
14204887Schin 				{
14214887Schin 					if (value)
14224887Schin 						goto ro;
14234887Schin 					s = buffer(s);
14244887Schin 					sfclose(tmp);
14254887Schin 					return s;
14264887Schin 				}
14274887Schin 				sfclose(tmp);
14284887Schin 			}
14294887Schin 		}
14304887Schin 		else if (streq(name + n - 3, "DIR"))
14314887Schin 		{
14324887Schin 			Lookup_t		altlook;
14334887Schin 			char			altname[ALT];
14344887Schin 
14354887Schin 			static const char*	dirs[] = { "/usr/lib", "/usr", null };
14364887Schin 
14374887Schin 			strcpy(altname, name);
14384887Schin 			altname[n - 3] = 0;
14394887Schin 			if (lookup(&altlook, altname, flags))
14404887Schin 			{
14414887Schin 				if (value)
14424887Schin 				{
14434887Schin 					errno = EINVAL;
14444887Schin 					if (conferror)
14454887Schin 						(*conferror)(&state, &state, 2, "%s: cannot set value", altname);
14464887Schin 					return (flags & ASTCONF_error) ? (char*)0 : null;
14474887Schin 				}
14484887Schin 				return print(NiL, &altlook, altname, path, flags, conferror);
14494887Schin 			}
14504887Schin 			for (s = altname; *s; s++)
14514887Schin 				if (isupper(*s))
14524887Schin 					*s = tolower(*s);
14534887Schin 			if (tmp = sfstropen())
14544887Schin 			{
14554887Schin 				for (n = 0; n < elementsof(dirs); n++)
14564887Schin 				{
14574887Schin 					sfprintf(tmp, "%s/%s/.", dirs[n], altname);
14584887Schin 					if ((s = sfstruse(tmp)) && !access(s, F_OK))
14594887Schin 					{
14604887Schin 						if (value)
14614887Schin 							goto ro;
14624887Schin 						s = buffer(s);
14634887Schin 						sfclose(tmp);
14644887Schin 						return s;
14654887Schin 					}
14664887Schin 				}
14674887Schin 				sfclose(tmp);
14684887Schin 			}
14694887Schin 		}
14704887Schin 	}
14714887Schin 	if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(look.name, path, value, flags, conferror)))
14724887Schin 		return s;
14734887Schin 	errno = EINVAL;
14744887Schin 	if (conferror && !(flags & ASTCONF_system))
14754887Schin 		(*conferror)(&state, &state, 2, "%s: unknown name", name);
14764887Schin 	return (flags & ASTCONF_error) ? (char*)0 : null;
14774887Schin }
14784887Schin 
14794887Schin /*
14804887Schin  * astconf() never returns 0
14814887Schin  */
14824887Schin 
14834887Schin char*
14844887Schin astconf(const char* name, const char* path, const char* value)
14854887Schin {
14864887Schin 	return astgetconf(name, path, value, 0, 0);
14874887Schin }
14884887Schin 
14894887Schin /*
14904887Schin  * set discipline function to be called when features change
14914887Schin  * old discipline function returned
14924887Schin  */
14934887Schin 
14944887Schin Ast_confdisc_f
14954887Schin astconfdisc(Ast_confdisc_f new_notify)
14964887Schin {
14974887Schin 	Ast_confdisc_f	old_notify;
14984887Schin 
14994887Schin 	INITIALIZE();
15004887Schin 	old_notify = state.notify;
15014887Schin 	state.notify = new_notify;
15024887Schin 	return old_notify;
15034887Schin }
15044887Schin 
15054887Schin /*
15064887Schin  * list all name=value entries on sp
15074887Schin  * path==0 implies path=="/"
15084887Schin  */
15094887Schin 
15104887Schin void
15114887Schin astconflist(Sfio_t* sp, const char* path, int flags, const char* pattern)
15124887Schin {
15134887Schin 	char*		s;
15144887Schin 	char*		f;
15154887Schin 	char*		call;
15164887Schin 	Feature_t*	fp;
15174887Schin 	Lookup_t	look;
15184887Schin 	regex_t		re;
15194887Schin 	regdisc_t	redisc;
15204887Schin 	int		olderrno;
15214887Schin 	char		flg[8];
15224887Schin #ifdef _pth_getconf_a
15234887Schin 	Proc_t*		proc;
15244887Schin 	Sfio_t*		pp;
15254887Schin #endif
15264887Schin 
15274887Schin 	INITIALIZE();
15284887Schin 	if (!path)
15294887Schin 		path = root;
15304887Schin 	else if (access(path, F_OK))
15314887Schin 	{
15324887Schin 		errorf(&state, &state, 2, "%s: not found", path);
15334887Schin 		return;
15344887Schin 	}
15354887Schin 	olderrno = errno;
15364887Schin 	look.flags = 0;
15374887Schin 	if (!(flags & (ASTCONF_read|ASTCONF_write|ASTCONF_parse)))
15384887Schin 		flags |= ASTCONF_read|ASTCONF_write;
15394887Schin 	else if (flags & ASTCONF_parse)
15404887Schin 		flags |= ASTCONF_write;
15414887Schin 	if (!(flags & (ASTCONF_matchcall|ASTCONF_matchname|ASTCONF_matchstandard)))
15424887Schin 		pattern = 0;
15434887Schin 	if (pattern)
15444887Schin 	{
15454887Schin 		memset(&redisc, 0, sizeof(redisc));
15464887Schin 		redisc.re_version = REG_VERSION;
15474887Schin 		redisc.re_errorf = (regerror_t)errorf;
15484887Schin 		re.re_disc = &redisc;
15494887Schin 		if (regcomp(&re, pattern, REG_DISCIPLINE|REG_EXTENDED|REG_LENIENT|REG_NULL))
15504887Schin 			return;
15514887Schin 	}
15524887Schin 	if (flags & ASTCONF_read)
15534887Schin 	{
15544887Schin 		for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
15554887Schin 		{
15564887Schin 			if (pattern)
15574887Schin 			{
15584887Schin 				if (flags & ASTCONF_matchcall)
15594887Schin 				{
15604887Schin 					if (regexec(&re, prefix[look.conf->call + CONF_call].name, 0, NiL, 0))
15614887Schin 						continue;
15624887Schin 				}
15634887Schin 				else if (flags & ASTCONF_matchname)
15644887Schin 				{
15654887Schin 					if (regexec(&re, look.conf->name, 0, NiL, 0))
15664887Schin 						continue;
15674887Schin 				}
15684887Schin 				else if (flags & ASTCONF_matchstandard)
15694887Schin 				{
15704887Schin 					if (regexec(&re, prefix[look.conf->standard].name, 0, NiL, 0))
15714887Schin 						continue;
15724887Schin 				}
15734887Schin 			}
15744887Schin 			print(sp, &look, NiL, path, flags, errorf);
15754887Schin 		}
15764887Schin #ifdef _pth_getconf_a
15774887Schin 		if (pp = nativeconf(&proc, _pth_getconf_a))
15784887Schin 		{
15794887Schin 			call = "GC";
15804887Schin 			while (f = sfgetr(pp, '\n', 1))
15814887Schin 			{
15824887Schin 				for (s = f; *s && *s != '=' && *s != ':' && !isspace(*s); s++);
15834887Schin 				if (*s)
15844887Schin 					for (*s++ = 0; isspace(*s); s++);
15854887Schin 				if (!lookup(&look, f, flags))
15864887Schin 				{
15874887Schin 					if (flags & ASTCONF_table)
15884887Schin 					{
15894887Schin 						if (look.standard < 0)
15904887Schin 							look.standard = 0;
15914887Schin 						if (look.section < 1)
15924887Schin 							look.section = 1;
15934887Schin 						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);
15944887Schin 					}
15954887Schin 					else if (flags & ASTCONF_parse)
15964887Schin 						sfprintf(sp, "%s %s - %s\n", state.id, f, s);
15974887Schin 					else
15984887Schin 						sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
15994887Schin 				}
16004887Schin 			}
16014887Schin 			sfclose(pp);
16024887Schin 			procclose(proc);
16034887Schin 		}
16044887Schin #endif
16054887Schin 	}
16064887Schin 	if (flags & ASTCONF_write)
16074887Schin 	{
16084887Schin 		call = "AC";
16094887Schin 		for (fp = state.features; fp; fp = fp->next)
16104887Schin 		{
16114887Schin 			if (pattern)
16124887Schin 			{
16134887Schin 				if (flags & ASTCONF_matchcall)
16144887Schin 				{
16154887Schin 					if (regexec(&re, call, 0, NiL, 0))
16164887Schin 						continue;
16174887Schin 				}
16184887Schin 				else if (flags & ASTCONF_matchname)
16194887Schin 				{
16204887Schin 					if (regexec(&re, fp->name, 0, NiL, 0))
16214887Schin 						continue;
16224887Schin 				}
16234887Schin 				else if (flags & ASTCONF_matchstandard)
16244887Schin 				{
16254887Schin 					if (regexec(&re, prefix[fp->standard].name, 0, NiL, 0))
16264887Schin 						continue;
16274887Schin 				}
16284887Schin 			}
16294887Schin 			if (!(s = feature(fp->name, path, NiL, 0, 0)) || !*s)
16304887Schin 				s = "0";
16314887Schin 			if (flags & ASTCONF_table)
16324887Schin 			{
16334887Schin 				f = flg;
16344887Schin 				if (fp->flags & CONF_ALLOC)
16354887Schin 					*f++ = 'A';
16364887Schin 				if (fp->flags & CONF_READONLY)
16374887Schin 					*f++ = 'R';
16384887Schin 				if (f == flg)
16394887Schin 					*f++ = 'X';
16404887Schin 				*f = 0;
16414887Schin 				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);
16424887Schin 			}
16434887Schin 			else if (flags & ASTCONF_parse)
16444887Schin 				sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
16454887Schin 			else
16464887Schin 				sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
16474887Schin 		}
16484887Schin 	}
16494887Schin 	if (pattern)
16504887Schin 		regfree(&re);
16514887Schin 	errno = olderrno;
16524887Schin }
1653