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