14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1985-2009 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 29*10898Sroland.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 43*10898Sroland.mainz@nrubsig.org #ifndef DEBUG_astconf 44*10898Sroland.mainz@nrubsig.org #define DEBUG_astconf 0 45*10898Sroland.mainz@nrubsig.org #endif 46*10898Sroland.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 76*10898Sroland.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) 78*10898Sroland.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; 99*10898Sroland.mainz@nrubsig.org char* std; 100*10898Sroland.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 { 119*10898Sroland.mainz@nrubsig.org #define OP_conformance 0 1204887Schin { 121*10898Sroland.mainz@nrubsig.org &dynamic[OP_conformance+1], 1224887Schin "CONFORMANCE", 1234887Schin "ast", 1244887Schin "standard", 125*10898Sroland.mainz@nrubsig.org "ast", 1264887Schin 11, 1274887Schin CONF_AST, 1284887Schin 0, 1294887Schin OP_conformance 1304887Schin }, 131*10898Sroland.mainz@nrubsig.org #define OP_fs_3d 1 1324887Schin { 133*10898Sroland.mainz@nrubsig.org &dynamic[OP_fs_3d+1], 1344887Schin "FS_3D", 1354887Schin &null[0], 1364887Schin "0", 137*10898Sroland.mainz@nrubsig.org 0, 1384887Schin 5, 1394887Schin CONF_AST, 1404887Schin 0, 1414887Schin OP_fs_3d 1424887Schin }, 143*10898Sroland.mainz@nrubsig.org #define OP_getconf 2 1444887Schin { 145*10898Sroland.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, 153*10898Sroland.mainz@nrubsig.org 0, 1544887Schin 7, 1554887Schin CONF_AST, 1564887Schin CONF_READONLY, 1574887Schin OP_getconf 1584887Schin }, 159*10898Sroland.mainz@nrubsig.org #define OP_hosttype 3 1604887Schin { 161*10898Sroland.mainz@nrubsig.org &dynamic[OP_hosttype+1], 1624887Schin "HOSTTYPE", 1634887Schin HOSTTYPE, 1644887Schin 0, 165*10898Sroland.mainz@nrubsig.org 0, 1664887Schin 8, 1674887Schin CONF_AST, 1684887Schin CONF_READONLY, 1694887Schin OP_hosttype 1704887Schin }, 171*10898Sroland.mainz@nrubsig.org #define OP_libpath 4 1724887Schin { 173*10898Sroland.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, 181*10898Sroland.mainz@nrubsig.org 0, 1824887Schin 7, 1834887Schin CONF_AST, 1844887Schin 0, 1854887Schin OP_libpath 1864887Schin }, 187*10898Sroland.mainz@nrubsig.org #define OP_libprefix 5 1884887Schin { 189*10898Sroland.mainz@nrubsig.org &dynamic[OP_libprefix+1], 1904887Schin "LIBPREFIX", 1914887Schin #ifdef CONF_LIBPREFIX 1924887Schin CONF_LIBPREFIX, 1934887Schin #else 1944887Schin "lib", 1954887Schin #endif 1964887Schin 0, 197*10898Sroland.mainz@nrubsig.org 0, 1984887Schin 9, 1994887Schin CONF_AST, 2004887Schin 0, 2014887Schin OP_libprefix 2024887Schin }, 203*10898Sroland.mainz@nrubsig.org #define OP_libsuffix 6 2044887Schin { 205*10898Sroland.mainz@nrubsig.org &dynamic[OP_libsuffix+1], 2064887Schin "LIBSUFFIX", 2074887Schin #ifdef CONF_LIBSUFFIX 2084887Schin CONF_LIBSUFFIX, 2094887Schin #else 2104887Schin ".so", 2114887Schin #endif 2124887Schin 0, 213*10898Sroland.mainz@nrubsig.org 0, 2144887Schin 9, 2154887Schin CONF_AST, 2164887Schin 0, 2174887Schin OP_libsuffix 2184887Schin }, 219*10898Sroland.mainz@nrubsig.org #define OP_path_attributes 7 2204887Schin { 221*10898Sroland.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], 229*10898Sroland.mainz@nrubsig.org 0, 2304887Schin 15, 2314887Schin CONF_AST, 2324887Schin CONF_READONLY, 2334887Schin OP_path_attributes 2344887Schin }, 235*10898Sroland.mainz@nrubsig.org #define OP_path_resolve 8 2364887Schin { 237*10898Sroland.mainz@nrubsig.org &dynamic[OP_path_resolve+1], 2384887Schin "PATH_RESOLVE", 2394887Schin &null[0], 240*10898Sroland.mainz@nrubsig.org "physical", 2414887Schin "metaphysical", 2424887Schin 12, 2434887Schin CONF_AST, 2444887Schin 0, 2454887Schin OP_path_resolve 2464887Schin }, 247*10898Sroland.mainz@nrubsig.org #define OP_universe 9 2484887Schin { 2494887Schin 0, 2504887Schin "UNIVERSE", 2514887Schin &null[0], 2524887Schin "att", 253*10898Sroland.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 271*10898Sroland.mainz@nrubsig.org int std; 272*10898Sroland.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 287*10898Sroland.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* 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* 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; 314*10898Sroland.mainz@nrubsig.org register char* p; 3154887Schin register int n; 3164887Schin 317*10898Sroland.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 } 398*10898Sroland.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; 402*10898Sroland.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++); 455*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 456*10898Sroland.mainz@nrubsig.org error(-3, "astconf synthesize %s", state.data - state.prefix); 457*10898Sroland.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 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 491*10898Sroland.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: 509*10898Sroland.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 518*10898Sroland.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 } 591*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 592*10898Sroland.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); 593*10898Sroland.mainz@nrubsig.org #endif 5944887Schin synthesize(fp, path, ok ? succeed : fail); 5954887Schin } 5964887Schin 5974887Schin /* 5984887Schin * format synthesized value 5994887Schin */ 6004887Schin 6014887Schin static char* 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 607*10898Sroland.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: 618*10898Sroland.mainz@nrubsig.org if (value && STANDARD(value)) 619*10898Sroland.mainz@nrubsig.org value = fp->std; 620*10898Sroland.mainz@nrubsig.org n = state.std = streq(fp->value, fp->std); 621*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 622*10898Sroland.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); 623*10898Sroland.mainz@nrubsig.org #endif 6244887Schin if (!synthesize(fp, path, value)) 625*10898Sroland.mainz@nrubsig.org initialize(fp, path, NiL, fp->std, fp->value); 626*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 627*10898Sroland.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); 628*10898Sroland.mainz@nrubsig.org #endif 629*10898Sroland.mainz@nrubsig.org if (!n && STANDARD(fp->value)) 630*10898Sroland.mainz@nrubsig.org { 631*10898Sroland.mainz@nrubsig.org state.std = 1; 6324887Schin for (sp = state.features; sp; sp = sp->next) 633*10898Sroland.mainz@nrubsig.org if (sp->std && sp->op && sp->op != OP_conformance) 634*10898Sroland.mainz@nrubsig.org astconf(sp->name, path, sp->std); 635*10898Sroland.mainz@nrubsig.org } 636*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 637*10898Sroland.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); 638*10898Sroland.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)) 677*10898Sroland.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) 683*10898Sroland.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, "=")) 712*10898Sroland.mainz@nrubsig.org { 713*10898Sroland.mainz@nrubsig.org if (state.synthesizing) 714*10898Sroland.mainz@nrubsig.org { 715*10898Sroland.mainz@nrubsig.org if (!(fp->flags & CONF_ALLOC)) 716*10898Sroland.mainz@nrubsig.org fp->value = 0; 717*10898Sroland.mainz@nrubsig.org n = strlen(value); 718*10898Sroland.mainz@nrubsig.org if (!(fp->value = newof(fp->value, char, n, 1))) 719*10898Sroland.mainz@nrubsig.org fp->value = null; 720*10898Sroland.mainz@nrubsig.org else 721*10898Sroland.mainz@nrubsig.org { 722*10898Sroland.mainz@nrubsig.org fp->flags |= CONF_ALLOC; 723*10898Sroland.mainz@nrubsig.org memcpy(fp->value, value, n); 724*10898Sroland.mainz@nrubsig.org fp->value[n] = 0; 725*10898Sroland.mainz@nrubsig.org } 726*10898Sroland.mainz@nrubsig.org } 727*10898Sroland.mainz@nrubsig.org else 728*10898Sroland.mainz@nrubsig.org synthesize(fp, path, value); 729*10898Sroland.mainz@nrubsig.org } 7308462SApril.Chin@Sun.COM else 731*10898Sroland.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); 761*10898Sroland.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 } 777*10898Sroland.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; 781*10898Sroland.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 = # 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; 866*10898Sroland.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; 873*10898Sroland.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; 908*10898Sroland.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; 963*10898Sroland.mainz@nrubsig.org #if DEBUG_astconf 964*10898Sroland.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" 965*10898Sroland.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 { 1094*10898Sroland.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 { 1120*10898Sroland.mainz@nrubsig.org if (streq(p->name, "VERSION")) 11214887Schin { 11224887Schin 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 1312*10898Sroland.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