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