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