astconf.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* string interface to confstr(),pathconf(),sysconf(),sysinfo()
* extended to allow some features to be set per-process
*/
static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2012-05-01 $\0\n";
#include "univlib.h"
#include <ast.h>
#include <error.h>
#include <fs3d.h>
#include <ctype.h>
#include <regex.h>
#include <proc.h>
#include <ls.h>
#include "conftab.h"
#ifndef DEBUG_astconf
#define DEBUG_astconf 0
#endif
#ifndef _pth_getconf
#define ASTCONF_system 0
#endif
#if _sys_systeminfo
# if !_lib_sysinfo
# if _lib_systeminfo
# define _lib_sysinfo 1
# define sysinfo(a,b,c) systeminfo(a,b,c)
# else
# if _lib_syscall && _sys_syscall
# if defined(SYS_systeminfo)
# define _lib_sysinfo 1
# endif
# endif
# endif
# endif
#else
#endif
#define CONF_ERROR (CONF_USER<<0)
#define MAXVAL 256
#endif
#ifndef _UNIV_DEFAULT
#define _UNIV_DEFAULT "att"
#endif
static char null[1];
typedef struct Feature_s
{
const char* name;
char* value;
char* std;
char* ast;
short length;
short standard;
unsigned int flags;
short op;
} Feature_t;
typedef struct Lookup_s
{
const char* name;
unsigned int flags;
short call;
short standard;
short section;
} Lookup_t;
{
#define OP_architecture 0
{
"ARCHITECTURE",
&null[0],
0,
0,
12,
0,
},
#define OP_conformance 1
{
"CONFORMANCE",
"ast",
"standard",
"ast",
11,
0,
},
#define OP_fs_3d 2
{
"FS_3D",
&null[0],
"0",
0,
5,
0,
},
#define OP_getconf 3
{
"GETCONF",
#ifdef _pth_getconf
#else
&null[0],
#endif
0,
0,
7,
},
#define OP_hosttype 4
{
"HOSTTYPE",
0,
0,
8,
},
#define OP_libpath 5
{
"LIBPATH",
#ifdef CONF_LIBPATH
#else
&null[0],
#endif
0,
0,
7,
0,
},
#define OP_libprefix 6
{
"LIBPREFIX",
#ifdef CONF_LIBPREFIX
#else
"lib",
#endif
0,
0,
9,
0,
},
#define OP_libsuffix 7
{
"LIBSUFFIX",
#ifdef CONF_LIBSUFFIX
#else
".so",
#endif
0,
0,
9,
0,
},
#define OP_path_attributes 8
{
"PATH_ATTRIBUTES",
#if _WINIX
"c",
#else
&null[0],
#endif
&null[0],
0,
15,
},
#define OP_path_resolve 9
{
"PATH_RESOLVE",
&null[0],
"physical",
"metaphysical",
12,
0,
},
#define OP_universe 10
{
0,
"UNIVERSE",
&null[0],
"att",
0,
8,
0,
},
{
0
}
};
typedef struct State_s
{
const char* id;
const char* name;
const char* standard;
const char* strict;
int std;
/* default initialization from here down */
int prefix;
int synthesizing;
char* data;
char* last;
} State_t;
static State_t state = { "getconf", "_AST_FEATURES", "CONFORMANCE = standard", "POSIXLY_CORRECT", dynamic, -1 };
/*
* return fmtbuf() copy of s
*/
static char*
buffer(char* s)
{
}
/*
* synthesize state for fp
* fp==0 initializes from getenv(state.name)
* value==0 just does lookup
* otherwise state is set to value
*/
static char*
{
register char* s;
register char* d;
register char* v;
register char* p;
register int n;
#if DEBUG_astconf
if (fp)
error(-6, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp->name, path, value, fp, state.synthesizing ? " SYNTHESIZING" : "");
#endif
if (state.synthesizing)
return null;
{
char* se;
char* de;
char* ve;
n += strlen(s) + 1;
n = roundof(n, 32);
return 0;
if (s)
for (;;)
{
for (d = s; *d && !isspace(*d); d++);
for (v = d; *v && !isspace(*v); v++);
if (!*v)
break;
if (*ve)
*ve = 0;
else
ve = 0;
*de = 0;
*se = 0;
feature(0, s, d, v, 0, 0);
*se = ' ';
*de = ' ';
if (!ve)
break;
*ve++ = ' ';
}
state.synthesizing = 0;
}
if (!fp)
{
if (!value)
return 0;
goto ok;
}
for (;;)
{
while (isspace(*d))
d++;
if (!*d)
break;
{
if (!value)
{
for (d += n + 1; *d && !isspace(*d); d++);
for (; isspace(*d); d++);
for (s = d; *s && !isspace(*s); s++);
n = s - d;
value = (const char*)d;
goto ok;
}
for (s = p = d + n + 1; *s && !isspace(*s); s++);
for (; isspace(*s); s++);
for (v = s; *s && !isspace(*s); s++);
n = s - v;
if ((!path || *path == *p && strlen(path) == (v - p - 1) && !memcmp(path, p, v - p - 1)) && strneq(v, value, n))
goto ok;
for (; isspace(*s); s++);
if (*s)
for (; *d = *s++; d++);
d--;
break;
}
for (; *d && !isspace(*d); d++);
for (; isspace(*d); d++);
for (; *d && !isspace(*d); d++);
for (; isspace(*d); d++);
for (; *d && !isspace(*d); d++);
}
if (!value)
{
{
else
}
return 0;
}
if (!value[0])
value = "0";
path = "-";
{
int c;
int i;
c = roundof(c, 32);
return 0;
}
*d++ = ' ';
*d++ = ' ';
for (s = (char*)path; *d = *s++; d++);
*d++ = ' ';
for (s = (char*)value; *d = *s++; d++);
#if DEBUG_astconf
#endif
n = s - (char*)value - 1;
ok:
n = 0;
else
{
}
}
/*
* initialize the value for fp
* if command!=0 then it is checked for on $PATH
* synthesize(fp,path,succeed) called on success
* otherwise synthesize(fp,path,fail) called
*/
static void
initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
{
register char* p;
register int ok = 1;
#if DEBUG_astconf
error(-6, "astconf initialize name=%s path=%s command=%s succeed=%s fail=%s fp=%p%s", fp->name, path, command, succeed, fail, fp, state.synthesizing ? " SYNTHESIZING" : "");
#endif
{
case OP_architecture:
ok = 1;
break;
case OP_conformance:
break;
case OP_hosttype:
ok = 1;
break;
case OP_path_attributes:
ok = 1;
break;
case OP_path_resolve:
break;
case OP_universe:
/*FALLTHROUGH...*/
default:
if (p = getenv("PATH"))
{
register int r = 1;
register char* d = p;
#if DEBUG_astconf
#endif
{
for (;;)
{
switch (*p++)
{
case 0:
break;
case ':':
{
if (r = p - d - 1)
{
{
ok = 1;
break;
}
}
d = p;
}
r = 1;
continue;
case '/':
if (r)
{
r = 0;
{
if (p[0] == 'u' && p[1] == 's' && p[2] == 'r' && p[3] == '/')
for (p += 4; *p == '/'; p++);
if (p[0] == 'b' && p[1] == 'i' && p[2] == 'n')
{
for (p += 3; *p == '/'; p++);
if (!*p || *p == ':')
break;
}
}
}
{
{
ok = 1;
break;
}
{
ok = 0;
break;
}
}
continue;
default:
r = 0;
continue;
}
break;
}
}
else
ok = 1;
}
break;
}
#if DEBUG_astconf
error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s ok=%d", state.std, fp->name, ok ? succeed : fail, fp->std, fp->ast, fp->value, ok);
#endif
}
/*
* format synthesized value
*/
static char*
format(register Feature_t* fp, const char* path, const char* value, unsigned int flags, Error_f conferror)
{
register int n;
#else
#endif
#if DEBUG_astconf
error(-6, "astconf format name=%s path=%s value=%s flags=%04x fp=%p%s", fp->name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
#endif
if (value)
{
case OP_architecture:
{
{
break;
}
{
break;
}
}
#if _X64_
#else
#endif
#else
#endif
break;
case OP_conformance:
#if DEBUG_astconf
error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
#endif
#if DEBUG_astconf
error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
#endif
{
}
#if DEBUG_astconf
error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
#endif
break;
case OP_fs_3d:
break;
case OP_hosttype:
break;
case OP_path_attributes:
#ifdef _PC_PATH_ATTRIBUTES
{
register char* s;
register char* e;
intmax_t v;
/*
* _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
*/
return 0;
for (n = 'a'; n <= 'z'; n++)
if (v & (1 << (n - 'a')))
{
*s++ = n;
if (s >= e)
break;
}
*s = 0;
}
#endif
break;
case OP_path_resolve:
break;
case OP_universe:
#if _lib_universe
if (value)
#else
#ifdef UNIV_MAX
n = 0;
if (value)
{
n++;
if (n >= univ_max)
{
if (conferror)
return 0;
}
}
#ifdef ATT_UNIV
n = setuniverse(n + 1);
if (!value && n > 0)
setuniverse(n);
#else
#endif
if (n <= 0 || n >= univ_max)
n = 1;
#else
{
if (state.synthesizing)
{
else
{
}
}
else
}
else
#endif
#endif
break;
default:
else
break;
}
}
/*
* value==0 get feature name
* value!=0 set feature name
* 0 returned if error or not defined; otherwise previous value
*/
static char*
feature(register Feature_t* fp, const char* name, const char* path, const char* value, unsigned int flags, Error_f conferror)
{
register int n;
if (!fp)
#if DEBUG_astconf
error(-6, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
#endif
if (!fp)
{
if (!value)
return 0;
return 0;
{
if (conferror)
return 0;
}
}
else if (value)
{
{
if (conferror)
return 0;
}
return 0;
}
else
}
/*
* binary search for name in conf[]
*/
static int
{
register int v;
register int c;
char* e;
const Prefix_t* p;
while (*name == '_')
name++;
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] == '_')))
{
if (p->call < 0)
{
break;
}
else
{
break;
}
{
e++;
if (*e)
break;
return 1;
}
{
name += 2;
}
goto again;
}
#if HUH_2006_02_10
#endif
#if DEBUG_astconf
error(-6, "astconf normal name=%s standard=%d section=%d call=%d flags=%04x elements=%d", look->name, look->standard, look->section, look->call, flags, conf_elements);
#endif
c = *((unsigned char*)name);
{
#if DEBUG_astconf
#endif
{
do
{
goto found;
{
goto found;
}
break;
}
else if (v > 0)
else
}
return 0;
#if DEBUG_astconf
error(-6, "astconf lookup name=%s standard=%d:%d section=%d:%d call=%d:%d", look->name, look->standard, mid->standard, look->section, mid->section, look->call, mid->call);
#endif
return 1;
}
/*
* return a tolower'd copy of s
*/
static char*
fmtlower(register const char* s)
{
register int c;
register char* t;
char* b;
while (c = *s++)
{
if (isupper(c))
c = tolower(c);
*t++ = c;
}
*t = 0;
return b;
}
/*
* print value line for p
* if !name then value prefixed by "p->name="
* if (flags & CONF_MINMAX) then default minmax value used
*/
static char*
print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
{
char* call;
char* f;
const char* s;
int i;
int n;
int olderrno;
int drop;
int defined;
intmax_t v;
char flg[16];
if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
flags |= CONF_PREFIXED;
errno = 0;
#if DEBUG_astconf
error(-5, "astconf name=%s:%s:%s standard=%d section=%d call=%s op=%d flags=|%s%s%s%s%s:|%s%s%s%s%s%s%s%s%s%s"
);
#endif
{
goto bad;
{
switch (p->call)
{
case CONF_pathconf:
{
goto bad;
}
break;
default:
{
goto bad;
}
break;
}
#ifdef _pth_getconf
if (p->flags & CONF_DEFER_CALL)
goto bad;
#endif
}
else
{
{
goto bad;
}
#ifdef _pth_getconf
goto bad;
#endif
}
if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
goto bad;
}
s = 0;
defined = 1;
{
case CONF_confstr:
call = "confstr";
#if _lib_confstr
{
defined = 0;
v = -1;
}
else if (v > 0)
{
s = (const char*)buf;
}
else
defined = 0;
break;
#else
goto predef;
#endif
case CONF_pathconf:
call = "pathconf";
#if _lib_pathconf
defined = 0;
break;
#else
goto predef;
#endif
case CONF_sysconf:
call = "sysconf";
#if _lib_sysconf
defined = 0;
break;
#else
goto predef;
#endif
case CONF_sysinfo:
call = "sysinfo";
#if _lib_sysinfo
{
s = (const char*)buf;
}
else
defined = 0;
break;
#else
goto predef;
#endif
default:
call = "synthesis";
v = -1;
defined = 0;
break;
case 0:
call = 0;
{
{
close(i);
n--;
n--;
buf[n] = 0;
if (buf[0])
{
v = 0;
s = buf;
break;
}
}
}
if (p->flags & CONF_MINMAX_DEF)
{
if (!((p->flags & CONF_LIMIT_DEF)))
flags |= CONF_MINMAX;
listflags &= ~ASTCONF_system;
}
{
{
break;
}
}
if (flags & CONF_MINMAX)
{
{
break;
}
}
else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
{
break;
}
v = -1;
defined = 0;
break;
}
if (!defined)
{
if (!errno)
{
}
else if (flags & CONF_PREFIXED)
{
if (!sp)
{
if (conferror)
{
if (call)
else if (!(listflags & ASTCONF_system))
}
goto bad;
}
else
{
flags |= CONF_ERROR;
}
}
}
goto bad;
goto bad;
if (listflags & ASTCONF_table)
{
f = flg;
if (p->flags & CONF_DEFER_CALL)
*f++ = 'C';
if (p->flags & CONF_DEFER_MM)
*f++ = 'D';
if (p->flags & CONF_FEATURE)
*f++ = 'F';
if (p->flags & CONF_LIMIT)
*f++ = 'L';
if (p->flags & CONF_MINMAX)
*f++ = 'M';
if (p->flags & CONF_NOSECTION)
*f++ = 'N';
if (p->flags & CONF_PREFIXED)
*f++ = 'P';
if (p->flags & CONF_STANDARD)
*f++ = 'S';
if (p->flags & CONF_UNDERSCORE)
*f++ = 'U';
if (p->flags & CONF_NOUNDERSCORE)
*f++ = 'V';
if (p->flags & CONF_PREFIX_ONLY)
*f++ = 'W';
if (f == flg)
*f++ = 'X';
*f = 0;
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);
if (p->flags & CONF_LIMIT_DEF)
{
sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
else
}
if (p->flags & CONF_MINMAX_DEF)
{
sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
else
}
if (flags & CONF_ERROR)
else if (defined)
{
if (s)
sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
else if (v != -1)
else
}
}
else
{
{
if (!name)
{
if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
{
sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
if (p->section > 1)
}
}
if (flags & CONF_ERROR)
else if (defined)
{
if (s)
sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
else if (v != -1)
else
}
else
if (!name)
}
if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
{
if (p->flags & CONF_UNDERSCORE)
sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
if (p->section > 1)
{
defined = 1;
}
if (v != -1)
else if (defined)
else
}
}
if (drop)
{
else
call = "[ out of space ]";
return call;
}
bad:
}
/*
* return read stream to native getconf utility
*/
static Sfio_t*
{
#ifdef _pth_getconf
char* cmd[3];
long ops[2];
#if DEBUG_astconf
#endif
cmd[2] = 0;
ops[1] = 0;
{
{
return sp;
}
}
#endif
return 0;
}
/*
* value==0 gets value for name
* value!=0 sets value for name and returns previous value
* path==0 implies path=="/"
*
* settable return values are in permanent store
* non-settable return values copied to a tmp fmtbuf() buffer
*
* if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
* our_way();
*
* universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
* astgetconf("UNIVERSE", NiL, universe, 0, 0);
*
* if (flags&ASTCONF_error)!=0 then error return value is 0
* otherwise 0 not returned
*/
#define ALT 16
char*
{
register char* s;
int n;
#if __OBSOLETE__ < 20080101
{
}
conferror = 0;
#endif
if (!name)
{
if (path)
return null;
{
{
#if _HUH20000515 /* doesn't work for shell builtins */
#endif
INITIALIZE();
}
return null;
}
value = 0;
}
INITIALIZE();
if (!path)
if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
return s;
{
if (value)
{
ro:
if (conferror)
}
}
{
{
{
{
if (value)
goto ro;
s = buffer(s);
return s;
}
}
}
{
altname[n - 3] = 0;
{
if (value)
{
if (conferror)
}
}
for (s = altname; *s; s++)
if (isupper(*s))
*s = tolower(*s);
{
for (n = 0; n < elementsof(dirs); n++)
{
{
if (value)
goto ro;
s = buffer(s);
return s;
}
}
}
}
}
if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(0, look.name, path, value, flags, conferror)))
return s;
}
/*
* astconf() never returns 0
*/
char*
{
}
/*
* set discipline function to be called when features change
* old discipline function returned
*/
{
INITIALIZE();
return old_notify;
}
/*
* list all name=value entries on sp
* path==0 implies path=="/"
*/
void
{
char* s;
char* f;
char* call;
int olderrno;
char flg[8];
#ifdef _pth_getconf_a
#endif
INITIALIZE();
if (!path)
{
return;
}
else if (flags & ASTCONF_parse)
flags |= ASTCONF_write;
pattern = 0;
if (pattern)
{
return;
}
if (flags & ASTCONF_read)
{
{
if (pattern)
{
if (flags & ASTCONF_matchcall)
{
continue;
}
else if (flags & ASTCONF_matchname)
{
continue;
}
else if (flags & ASTCONF_matchstandard)
{
continue;
}
}
}
#ifdef _pth_getconf_a
{
call = "GC";
{
if (*s)
for (*s++ = 0; isspace(*s); s++);
{
if (flags & ASTCONF_table)
{
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);
}
else if (flags & ASTCONF_parse)
else
sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
}
}
}
#endif
}
if (flags & ASTCONF_write)
{
call = "AC";
{
if (pattern)
{
if (flags & ASTCONF_matchcall)
{
continue;
}
else if (flags & ASTCONF_matchname)
{
continue;
}
else if (flags & ASTCONF_matchstandard)
{
continue;
}
}
s = "0";
if (flags & ASTCONF_table)
{
f = flg;
*f++ = 'A';
*f++ = 'R';
if (f == flg)
*f++ = 'X';
*f = 0;
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);
}
else if (flags & ASTCONF_parse)
sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
else
sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
}
}
if (pattern)
}