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