14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1992-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * * 204887Schin ***********************************************************************/ 214887Schin #pragma prototyped 224887Schin /* 234887Schin * Glenn Fowler 244887Schin * AT&T Research 254887Schin * 264887Schin * getconf - get configuration values 274887Schin */ 284887Schin 294887Schin static const char usage[] = 30*8462SApril.Chin@Sun.COM "[-?\n@(#)$Id: getconf (AT&T Research) 2008-04-24 $\n]" 314887Schin USAGE_LICENSE 324887Schin "[+NAME?getconf - get configuration values]" 334887Schin "[+DESCRIPTION?\bgetconf\b displays the system configuration value for" 344887Schin " \aname\a. If \aname\a is a filesystem specific variable then" 354887Schin " the value is determined relative to \apath\a or the current" 364887Schin " directory if \apath\a is omitted. If \avalue\a is specified then" 374887Schin " \bgetconf\b attempts to change the process local value to \avalue\a." 384887Schin " \b-\b may be used in place of \apath\a when it is not relevant." 39*8462SApril.Chin@Sun.COM " If \apath\a is \b=\b then the the \avalue\a is cached and used" 40*8462SApril.Chin@Sun.COM " for subsequent tests in the calling and all child processes." 414887Schin " Only \bwritable\b variables may be set; \breadonly\b variables" 424887Schin " cannot be changed.]" 434887Schin "[+?The current value for \aname\a is written to the standard output. If" 444887Schin " \aname\a is valid but undefined then \bundefined\b is written to" 454887Schin " the standard output. If \aname\a is invalid or an error occurs in" 464887Schin " determining its value, then a diagnostic written to the standard error" 474887Schin " and \bgetconf\b exits with a non-zero exit status.]" 484887Schin "[+?More than one variable may be set or queried by providing the \aname\a" 494887Schin " \apath\a \avalue\a 3-tuple for each variable, specifying \b-\b for" 504887Schin " \avalue\a when querying.]" 514887Schin "[+?If no operands are specified then all known variables are written in" 524887Schin " \aname\a=\avalue\a form to the standard output, one per line." 534887Schin " Only one of \b--call\b, \b--name\b or \b--standard\b may be specified.]" 544887Schin "[+?This implementation uses the \bastgetconf\b(3) string interface to the native" 554887Schin " \bsysconf\b(2), \bconfstr\b(2), \bpathconf\b(2), and \bsysinfo\b(2)" 564887Schin " system calls. If \bgetconf\b on \b$PATH\b is not the default native" 574887Schin " \bgetconf\b, named by \b$(getconf GETCONF)\b, then \bastgetconf\b(3)" 584887Schin " checks only \bast\b specific extensions and the native system calls;" 594887Schin " invalid options and/or names not supported by \bastgetconf\b(3) cause" 604887Schin " the \bgetconf\b on \b$PATH\b to be executed.]" 614887Schin 624887Schin "[a:all?Call the native \bgetconf\b(1) with option \b-a\b.]" 634887Schin "[b:base?List base variable name sans call and standard prefixes.]" 644887Schin "[c:call?Display variables with call prefix that matches \aRE\a. The call" 654887Schin " prefixes are:]:[RE]{" 664887Schin " [+CS?\bconfstr\b(2)]" 674887Schin " [+PC?\bpathconf\b(2)]" 684887Schin " [+SC?\bsysconf\b(2)]" 694887Schin " [+SI?\bsysinfo\b(2)]" 704887Schin " [+XX?Constant value.]" 714887Schin "}" 724887Schin "[d:defined?Only display defined values when no operands are specified.]" 734887Schin "[l:lowercase?List variable names in lower case.]" 744887Schin "[n:name?Display variables with name that match \aRE\a.]:[RE]" 754887Schin "[p:portable?Display the named \bwritable\b variables and values in a form that" 764887Schin " can be directly executed by \bsh\b(1) to set the values. If \aname\a" 774887Schin " is omitted then all \bwritable\b variables are listed.]" 784887Schin "[q:quote?\"...\" quote values.]" 794887Schin "[r:readonly?Display the named \breadonly\b variables in \aname\a=\avalue\a form." 804887Schin " If \aname\a is omitted then all \breadonly\b variables are listed.]" 814887Schin "[s:standard?Display variables with standard prefix that matches \aRE\a." 824887Schin " Use the \b--table\b option to view all standard prefixes, including" 834887Schin " local additions. The standard prefixes available on all systems" 844887Schin " are:]:[RE]{" 854887Schin " [+AES]" 864887Schin " [+AST]" 874887Schin " [+C]" 884887Schin " [+GNU]" 894887Schin " [+POSIX]" 904887Schin " [+SVID]" 914887Schin " [+XBS5]" 924887Schin " [+XOPEN]" 934887Schin " [+XPG]" 944887Schin "}" 954887Schin "[t:table?Display the internal table that contains the name, standard," 964887Schin " standard section, and system call symbol prefix for each variable.]" 974887Schin "[w:writable?Display the named \bwritable\b variables in \aname\a=\avalue\a" 984887Schin " form. If \aname\a is omitted then all \bwritable\b variables are" 994887Schin " listed.]" 1004887Schin "[v:specification?Call the native \bgetconf\b(1) with option" 1014887Schin " \b-v\b \aname\a.]:[name]" 1024887Schin 1034887Schin "\n" 1044887Schin "\n[ name [ path [ value ] ] ... ]\n" 1054887Schin "\n" 1064887Schin 1074887Schin "[+ENVIRONMENT]{" 1084887Schin " [+_AST_FEATURES?Process local writable values that are different from" 1094887Schin " the default are stored in the \b_AST_FEATURES\b environment" 1104887Schin " variable. The \b_AST_FEATURES\b value is a space-separated" 1114887Schin " list of \aname\a \apath\a \avalue\a 3-tuples, where" 1124887Schin " \aname\a is the system configuration name, \apath\a is the" 1134887Schin " corresponding path, \b-\b if no path is applicable, and" 1144887Schin " \avalue\a is the system configuration value.]" 1154887Schin "}" 1164887Schin "[+SEE ALSO?\bpathchk\b(1), \bconfstr\b(2), \bpathconf\b(2)," 1174887Schin " \bsysconf\b(2), \bastgetconf\b(3)]" 1184887Schin ; 1194887Schin 1204887Schin #include <cmd.h> 1214887Schin #include <proc.h> 1224887Schin #include <ls.h> 1234887Schin 1244887Schin typedef struct Path_s 1254887Schin { 126*8462SApril.Chin@Sun.COM const char* path; 1274887Schin int len; 1284887Schin } Path_t; 1294887Schin 1304887Schin int 1314887Schin b_getconf(int argc, char** argv, void* context) 1324887Schin { 1334887Schin register char* name; 1344887Schin register char* path; 1354887Schin register char* value; 136*8462SApril.Chin@Sun.COM register const char* s; 137*8462SApril.Chin@Sun.COM register const char* t; 1384887Schin char* pattern; 1394887Schin char* native; 1404887Schin char* cmd; 1414887Schin Path_t* e; 1424887Schin Path_t* p; 1434887Schin int flags; 1444887Schin int n; 1454887Schin int i; 1464887Schin int m; 1474887Schin int q; 1484887Schin char** oargv; 1494887Schin char buf[PATH_MAX]; 1504887Schin Path_t std[64]; 1514887Schin struct stat st0; 1524887Schin struct stat st1; 1534887Schin 1544887Schin static const char empty[] = "-"; 1554887Schin static const Path_t equiv[] = { { "/bin", 4 }, { "/usr/bin", 8 } }; 1564887Schin 1574887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 1584887Schin oargv = argv; 1594887Schin if (*(native = astconf("GETCONF", NiL, NiL)) != '/') 1604887Schin native = 0; 1614887Schin flags = 0; 1624887Schin name = 0; 1634887Schin pattern = 0; 1644887Schin for (;;) 1654887Schin { 1664887Schin switch (optget(argv, usage)) 1674887Schin { 1684887Schin case 'a': 1694887Schin if (native) 1704887Schin goto defer; 1714887Schin continue; 1724887Schin case 'b': 1734887Schin flags |= ASTCONF_base; 1744887Schin continue; 1754887Schin case 'c': 1764887Schin flags |= ASTCONF_matchcall; 1774887Schin pattern = opt_info.arg; 1784887Schin continue; 1794887Schin case 'd': 1804887Schin flags |= ASTCONF_defined; 1814887Schin continue; 1824887Schin case 'l': 1834887Schin flags |= ASTCONF_lower; 1844887Schin continue; 1854887Schin case 'n': 1864887Schin flags |= ASTCONF_matchname; 1874887Schin pattern = opt_info.arg; 1884887Schin continue; 1894887Schin case 'p': 1904887Schin flags |= ASTCONF_parse; 1914887Schin continue; 1924887Schin case 'q': 1934887Schin flags |= ASTCONF_quote; 1944887Schin continue; 1954887Schin case 'r': 1964887Schin flags |= ASTCONF_read; 1974887Schin continue; 1984887Schin case 's': 1994887Schin flags |= ASTCONF_matchstandard; 2004887Schin pattern = opt_info.arg; 2014887Schin continue; 2024887Schin case 't': 2034887Schin flags |= ASTCONF_table; 2044887Schin continue; 2054887Schin case 'v': 2064887Schin if (native) 2074887Schin goto defer; 2084887Schin continue; 2094887Schin case 'w': 2104887Schin flags |= ASTCONF_write; 2114887Schin continue; 2124887Schin case ':': 2134887Schin if (native) 2144887Schin goto defer; 2154887Schin error(2, "%s", opt_info.arg); 2164887Schin break; 2174887Schin case '?': 2184887Schin error(ERROR_usage(2), "%s", opt_info.arg); 2194887Schin break; 2204887Schin } 2214887Schin break; 2224887Schin } 2234887Schin argv += opt_info.index; 2244887Schin if (!(name = *argv)) 2254887Schin path = 0; 2264887Schin else if (streq(name, empty)) 2274887Schin { 2284887Schin name = 0; 2294887Schin if (path = *++argv) 2304887Schin { 2314887Schin argv++; 2324887Schin if (streq(path, empty)) 2334887Schin path = 0; 2344887Schin } 2354887Schin } 2364887Schin if (error_info.errors || !name && *argv) 2374887Schin error(ERROR_usage(2), "%s", optusage(NiL)); 2384887Schin if (!name) 2394887Schin astconflist(sfstdout, path, flags, pattern); 2404887Schin else 2414887Schin { 2424887Schin flags = native ? (ASTCONF_system|ASTCONF_error) : 0; 2434887Schin do 2444887Schin { 2454887Schin if (!(path = *++argv)) 2464887Schin value = 0; 2474887Schin else 2484887Schin { 2494887Schin if (streq(path, empty)) 2504887Schin { 2514887Schin path = 0; 2524887Schin flags = 0; 2534887Schin } 2544887Schin if ((value = *++argv) && (streq(value, empty))) 2554887Schin { 2564887Schin value = 0; 2574887Schin flags = 0; 2584887Schin } 2594887Schin } 2604887Schin s = astgetconf(name, path, value, flags, errorf); 2614887Schin if (error_info.errors) 2624887Schin break; 2634887Schin if (!s) 2644887Schin goto defer; 2654887Schin if (!value) 2664887Schin { 2674887Schin if (flags & ASTCONF_write) 2684887Schin { 2694887Schin sfputr(sfstdout, name, ' '); 2704887Schin sfputr(sfstdout, path ? path : empty, ' '); 2714887Schin } 2724887Schin sfputr(sfstdout, s, '\n'); 2734887Schin } 2744887Schin } while (*argv && (name = *++argv)); 2754887Schin } 2764887Schin return error_info.errors != 0; 2774887Schin 2784887Schin defer: 2794887Schin 2804887Schin /* 2814887Schin * defer to argv[0] if absolute and it exists 2824887Schin */ 2834887Schin 2844887Schin if ((cmd = oargv[0]) && *cmd == '/' && !access(cmd, X_OK)) 2854887Schin goto found; 2864887Schin 2874887Schin /* 2884887Schin * defer to the first getconf on $PATH that is also on the standard PATH 2894887Schin */ 2904887Schin 2914887Schin e = std; 2924887Schin s = astconf("PATH", NiL, NiL); 2934887Schin q = !stat(equiv[0].path, &st0) && !stat(equiv[1].path, &st1) && st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev; 2944887Schin m = 0; 2954887Schin do 2964887Schin { 2974887Schin for (t = s; *s && *s != ':'; s++); 2984887Schin if ((n = s - t) && *t == '/') 2994887Schin { 3004887Schin if (q) 3014887Schin for (i = 0; i < 2; i++) 3024887Schin if (n == equiv[i].len && !strncmp(t, equiv[i].path, n)) 3034887Schin { 3044887Schin if (m & (i+1)) 3054887Schin t = 0; 3064887Schin else 3074887Schin { 3084887Schin m |= (i+1); 3094887Schin if (!(m & (!i+1))) 3104887Schin { 3114887Schin m |= (!i+1); 3124887Schin e->path = t; 3134887Schin e->len = n; 3144887Schin e++; 3154887Schin if (e >= &std[elementsof(std)]) 3164887Schin break; 3174887Schin t = equiv[!i].path; 3184887Schin n = equiv[!i].len; 3194887Schin } 3204887Schin } 3214887Schin } 3224887Schin if (t) 3234887Schin { 3244887Schin e->path = t; 3254887Schin e->len = n; 3264887Schin e++; 3274887Schin } 3284887Schin } 3294887Schin while (*s == ':') 3304887Schin s++; 3314887Schin } while (*s && e < &std[elementsof(std)]); 3324887Schin if (e < &std[elementsof(std)]) 3334887Schin { 3344887Schin e->len = strlen(e->path = "/usr/sbin"); 3354887Schin if (++e < &std[elementsof(std)]) 3364887Schin { 3374887Schin e->len = strlen(e->path = "/sbin"); 3384887Schin e++; 3394887Schin } 3404887Schin } 3414887Schin if (s = getenv("PATH")) 3424887Schin do 3434887Schin { 3444887Schin for (t = s; *s && *s != ':'; s++); 3454887Schin if ((n = s - t) && *t == '/') 3464887Schin { 3474887Schin for (p = std; p < e; p++) 3484887Schin if (p->len == n && !strncmp(t, p->path, n)) 3494887Schin { 3504887Schin sfsprintf(buf, sizeof(buf), "%-*.*s/%s", n, n, t, error_info.id); 3514887Schin if (!access(buf, X_OK)) 3524887Schin { 3534887Schin cmd = buf; 3544887Schin goto found; 3554887Schin } 3564887Schin } 3574887Schin } 3584887Schin while (*s == ':') 3594887Schin s++; 3604887Schin } while (*s); 3614887Schin 3624887Schin /* 3634887Schin * defer to the first getconf on the standard PATH 3644887Schin */ 3654887Schin 3664887Schin for (p = std; p < e; p++) 3674887Schin { 3684887Schin sfsprintf(buf, sizeof(buf), "%-*.*s/%s", p->len, p->len, p->path, error_info.id); 3694887Schin if (!access(buf, X_OK)) 3704887Schin { 3714887Schin cmd = buf; 3724887Schin goto found; 3734887Schin } 3744887Schin } 3754887Schin 3764887Schin /* 3774887Schin * out of deferrals 3784887Schin */ 3794887Schin 3804887Schin if (name) 3814887Schin error(4, "%s: unknown name -- no native getconf(1) to defer to", name); 3824887Schin else 3834887Schin error(4, "no native getconf(1) to defer to"); 3844887Schin return 2; 3854887Schin 3864887Schin found: 3874887Schin 3884887Schin /* 3894887Schin * don't blame us for crappy diagnostics 3904887Schin */ 3914887Schin 392*8462SApril.Chin@Sun.COM oargv[0] = cmd; 393*8462SApril.Chin@Sun.COM if ((n = sh_run(context, argc, oargv)) >= EXIT_NOEXEC) 3944887Schin error(ERROR_SYSTEM|2, "%s: exec error [%d]", cmd, n); 3954887Schin return n; 3964887Schin } 397