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