1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * * 20*4887Schin ***********************************************************************/ 21*4887Schin #pragma prototyped 22*4887Schin /* 23*4887Schin * Glenn Fowler 24*4887Schin * AT&T Research 25*4887Schin * 26*4887Schin * getconf - get configuration values 27*4887Schin */ 28*4887Schin 29*4887Schin static const char usage[] = 30*4887Schin "[-?\n@(#)$Id: getconf (AT&T Research) 2007-02-07 $\n]" 31*4887Schin USAGE_LICENSE 32*4887Schin "[+NAME?getconf - get configuration values]" 33*4887Schin "[+DESCRIPTION?\bgetconf\b displays the system configuration value for" 34*4887Schin " \aname\a. If \aname\a is a filesystem specific variable then" 35*4887Schin " the value is determined relative to \apath\a or the current" 36*4887Schin " directory if \apath\a is omitted. If \avalue\a is specified then" 37*4887Schin " \bgetconf\b attempts to change the process local value to \avalue\a." 38*4887Schin " \b-\b may be used in place of \apath\a when it is not relevant." 39*4887Schin " Only \bwritable\b variables may be set; \breadonly\b variables" 40*4887Schin " cannot be changed.]" 41*4887Schin "[+?The current value for \aname\a is written to the standard output. If" 42*4887Schin " \aname\a is valid but undefined then \bundefined\b is written to" 43*4887Schin " the standard output. If \aname\a is invalid or an error occurs in" 44*4887Schin " determining its value, then a diagnostic written to the standard error" 45*4887Schin " and \bgetconf\b exits with a non-zero exit status.]" 46*4887Schin "[+?More than one variable may be set or queried by providing the \aname\a" 47*4887Schin " \apath\a \avalue\a 3-tuple for each variable, specifying \b-\b for" 48*4887Schin " \avalue\a when querying.]" 49*4887Schin "[+?If no operands are specified then all known variables are written in" 50*4887Schin " \aname\a=\avalue\a form to the standard output, one per line." 51*4887Schin " Only one of \b--call\b, \b--name\b or \b--standard\b may be specified.]" 52*4887Schin "[+?This implementation uses the \bastgetconf\b(3) string interface to the native" 53*4887Schin " \bsysconf\b(2), \bconfstr\b(2), \bpathconf\b(2), and \bsysinfo\b(2)" 54*4887Schin " system calls. If \bgetconf\b on \b$PATH\b is not the default native" 55*4887Schin " \bgetconf\b, named by \b$(getconf GETCONF)\b, then \bastgetconf\b(3)" 56*4887Schin " checks only \bast\b specific extensions and the native system calls;" 57*4887Schin " invalid options and/or names not supported by \bastgetconf\b(3) cause" 58*4887Schin " the \bgetconf\b on \b$PATH\b to be executed.]" 59*4887Schin 60*4887Schin "[a:all?Call the native \bgetconf\b(1) with option \b-a\b.]" 61*4887Schin "[b:base?List base variable name sans call and standard prefixes.]" 62*4887Schin "[c:call?Display variables with call prefix that matches \aRE\a. The call" 63*4887Schin " prefixes are:]:[RE]{" 64*4887Schin " [+CS?\bconfstr\b(2)]" 65*4887Schin " [+PC?\bpathconf\b(2)]" 66*4887Schin " [+SC?\bsysconf\b(2)]" 67*4887Schin " [+SI?\bsysinfo\b(2)]" 68*4887Schin " [+XX?Constant value.]" 69*4887Schin "}" 70*4887Schin "[d:defined?Only display defined values when no operands are specified.]" 71*4887Schin "[l:lowercase?List variable names in lower case.]" 72*4887Schin "[n:name?Display variables with name that match \aRE\a.]:[RE]" 73*4887Schin "[p:portable?Display the named \bwritable\b variables and values in a form that" 74*4887Schin " can be directly executed by \bsh\b(1) to set the values. If \aname\a" 75*4887Schin " is omitted then all \bwritable\b variables are listed.]" 76*4887Schin "[q:quote?\"...\" quote values.]" 77*4887Schin "[r:readonly?Display the named \breadonly\b variables in \aname\a=\avalue\a form." 78*4887Schin " If \aname\a is omitted then all \breadonly\b variables are listed.]" 79*4887Schin "[s:standard?Display variables with standard prefix that matches \aRE\a." 80*4887Schin " Use the \b--table\b option to view all standard prefixes, including" 81*4887Schin " local additions. The standard prefixes available on all systems" 82*4887Schin " are:]:[RE]{" 83*4887Schin " [+AES]" 84*4887Schin " [+AST]" 85*4887Schin " [+C]" 86*4887Schin " [+GNU]" 87*4887Schin " [+POSIX]" 88*4887Schin " [+SVID]" 89*4887Schin " [+XBS5]" 90*4887Schin " [+XOPEN]" 91*4887Schin " [+XPG]" 92*4887Schin "}" 93*4887Schin "[t:table?Display the internal table that contains the name, standard," 94*4887Schin " standard section, and system call symbol prefix for each variable.]" 95*4887Schin "[w:writable?Display the named \bwritable\b variables in \aname\a=\avalue\a" 96*4887Schin " form. If \aname\a is omitted then all \bwritable\b variables are" 97*4887Schin " listed.]" 98*4887Schin "[v:specification?Call the native \bgetconf\b(1) with option" 99*4887Schin " \b-v\b \aname\a.]:[name]" 100*4887Schin 101*4887Schin "\n" 102*4887Schin "\n[ name [ path [ value ] ] ... ]\n" 103*4887Schin "\n" 104*4887Schin 105*4887Schin "[+ENVIRONMENT]{" 106*4887Schin " [+_AST_FEATURES?Process local writable values that are different from" 107*4887Schin " the default are stored in the \b_AST_FEATURES\b environment" 108*4887Schin " variable. The \b_AST_FEATURES\b value is a space-separated" 109*4887Schin " list of \aname\a \apath\a \avalue\a 3-tuples, where" 110*4887Schin " \aname\a is the system configuration name, \apath\a is the" 111*4887Schin " corresponding path, \b-\b if no path is applicable, and" 112*4887Schin " \avalue\a is the system configuration value.]" 113*4887Schin "}" 114*4887Schin "[+SEE ALSO?\bpathchk\b(1), \bconfstr\b(2), \bpathconf\b(2)," 115*4887Schin " \bsysconf\b(2), \bastgetconf\b(3)]" 116*4887Schin ; 117*4887Schin 118*4887Schin #include <cmd.h> 119*4887Schin #include <proc.h> 120*4887Schin #include <ls.h> 121*4887Schin 122*4887Schin typedef struct Path_s 123*4887Schin { 124*4887Schin char* path; 125*4887Schin int len; 126*4887Schin } Path_t; 127*4887Schin 128*4887Schin int 129*4887Schin b_getconf(int argc, char** argv, void* context) 130*4887Schin { 131*4887Schin register char* name; 132*4887Schin register char* path; 133*4887Schin register char* value; 134*4887Schin register char* s; 135*4887Schin register char* t; 136*4887Schin char* pattern; 137*4887Schin char* native; 138*4887Schin char* cmd; 139*4887Schin Path_t* e; 140*4887Schin Path_t* p; 141*4887Schin int flags; 142*4887Schin int n; 143*4887Schin int i; 144*4887Schin int m; 145*4887Schin int q; 146*4887Schin char** oargv; 147*4887Schin char buf[PATH_MAX]; 148*4887Schin Path_t std[64]; 149*4887Schin struct stat st0; 150*4887Schin struct stat st1; 151*4887Schin 152*4887Schin static const char empty[] = "-"; 153*4887Schin static const Path_t equiv[] = { { "/bin", 4 }, { "/usr/bin", 8 } }; 154*4887Schin 155*4887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 156*4887Schin oargv = argv; 157*4887Schin if (*(native = astconf("GETCONF", NiL, NiL)) != '/') 158*4887Schin native = 0; 159*4887Schin flags = 0; 160*4887Schin name = 0; 161*4887Schin pattern = 0; 162*4887Schin for (;;) 163*4887Schin { 164*4887Schin switch (optget(argv, usage)) 165*4887Schin { 166*4887Schin case 'a': 167*4887Schin if (native) 168*4887Schin goto defer; 169*4887Schin continue; 170*4887Schin case 'b': 171*4887Schin flags |= ASTCONF_base; 172*4887Schin continue; 173*4887Schin case 'c': 174*4887Schin flags |= ASTCONF_matchcall; 175*4887Schin pattern = opt_info.arg; 176*4887Schin continue; 177*4887Schin case 'd': 178*4887Schin flags |= ASTCONF_defined; 179*4887Schin continue; 180*4887Schin case 'l': 181*4887Schin flags |= ASTCONF_lower; 182*4887Schin continue; 183*4887Schin case 'n': 184*4887Schin flags |= ASTCONF_matchname; 185*4887Schin pattern = opt_info.arg; 186*4887Schin continue; 187*4887Schin case 'p': 188*4887Schin flags |= ASTCONF_parse; 189*4887Schin continue; 190*4887Schin case 'q': 191*4887Schin flags |= ASTCONF_quote; 192*4887Schin continue; 193*4887Schin case 'r': 194*4887Schin flags |= ASTCONF_read; 195*4887Schin continue; 196*4887Schin case 's': 197*4887Schin flags |= ASTCONF_matchstandard; 198*4887Schin pattern = opt_info.arg; 199*4887Schin continue; 200*4887Schin case 't': 201*4887Schin flags |= ASTCONF_table; 202*4887Schin continue; 203*4887Schin case 'v': 204*4887Schin if (native) 205*4887Schin goto defer; 206*4887Schin continue; 207*4887Schin case 'w': 208*4887Schin flags |= ASTCONF_write; 209*4887Schin continue; 210*4887Schin case ':': 211*4887Schin if (native) 212*4887Schin goto defer; 213*4887Schin error(2, "%s", opt_info.arg); 214*4887Schin break; 215*4887Schin case '?': 216*4887Schin error(ERROR_usage(2), "%s", opt_info.arg); 217*4887Schin break; 218*4887Schin } 219*4887Schin break; 220*4887Schin } 221*4887Schin argv += opt_info.index; 222*4887Schin if (!(name = *argv)) 223*4887Schin path = 0; 224*4887Schin else if (streq(name, empty)) 225*4887Schin { 226*4887Schin name = 0; 227*4887Schin if (path = *++argv) 228*4887Schin { 229*4887Schin argv++; 230*4887Schin if (streq(path, empty)) 231*4887Schin path = 0; 232*4887Schin } 233*4887Schin } 234*4887Schin if (error_info.errors || !name && *argv) 235*4887Schin error(ERROR_usage(2), "%s", optusage(NiL)); 236*4887Schin if (!name) 237*4887Schin astconflist(sfstdout, path, flags, pattern); 238*4887Schin else 239*4887Schin { 240*4887Schin flags = native ? (ASTCONF_system|ASTCONF_error) : 0; 241*4887Schin do 242*4887Schin { 243*4887Schin if (!(path = *++argv)) 244*4887Schin value = 0; 245*4887Schin else 246*4887Schin { 247*4887Schin if (streq(path, empty)) 248*4887Schin { 249*4887Schin path = 0; 250*4887Schin flags = 0; 251*4887Schin } 252*4887Schin if ((value = *++argv) && (streq(value, empty))) 253*4887Schin { 254*4887Schin value = 0; 255*4887Schin flags = 0; 256*4887Schin } 257*4887Schin } 258*4887Schin s = astgetconf(name, path, value, flags, errorf); 259*4887Schin if (error_info.errors) 260*4887Schin break; 261*4887Schin if (!s) 262*4887Schin goto defer; 263*4887Schin if (!value) 264*4887Schin { 265*4887Schin if (flags & ASTCONF_write) 266*4887Schin { 267*4887Schin sfputr(sfstdout, name, ' '); 268*4887Schin sfputr(sfstdout, path ? path : empty, ' '); 269*4887Schin } 270*4887Schin sfputr(sfstdout, s, '\n'); 271*4887Schin } 272*4887Schin } while (*argv && (name = *++argv)); 273*4887Schin } 274*4887Schin return error_info.errors != 0; 275*4887Schin 276*4887Schin defer: 277*4887Schin 278*4887Schin /* 279*4887Schin * defer to argv[0] if absolute and it exists 280*4887Schin */ 281*4887Schin 282*4887Schin if ((cmd = oargv[0]) && *cmd == '/' && !access(cmd, X_OK)) 283*4887Schin goto found; 284*4887Schin 285*4887Schin /* 286*4887Schin * defer to the first getconf on $PATH that is also on the standard PATH 287*4887Schin */ 288*4887Schin 289*4887Schin e = std; 290*4887Schin s = astconf("PATH", NiL, NiL); 291*4887Schin q = !stat(equiv[0].path, &st0) && !stat(equiv[1].path, &st1) && st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev; 292*4887Schin m = 0; 293*4887Schin do 294*4887Schin { 295*4887Schin for (t = s; *s && *s != ':'; s++); 296*4887Schin if ((n = s - t) && *t == '/') 297*4887Schin { 298*4887Schin if (q) 299*4887Schin for (i = 0; i < 2; i++) 300*4887Schin if (n == equiv[i].len && !strncmp(t, equiv[i].path, n)) 301*4887Schin { 302*4887Schin if (m & (i+1)) 303*4887Schin t = 0; 304*4887Schin else 305*4887Schin { 306*4887Schin m |= (i+1); 307*4887Schin if (!(m & (!i+1))) 308*4887Schin { 309*4887Schin m |= (!i+1); 310*4887Schin e->path = t; 311*4887Schin e->len = n; 312*4887Schin e++; 313*4887Schin if (e >= &std[elementsof(std)]) 314*4887Schin break; 315*4887Schin t = equiv[!i].path; 316*4887Schin n = equiv[!i].len; 317*4887Schin } 318*4887Schin } 319*4887Schin } 320*4887Schin if (t) 321*4887Schin { 322*4887Schin e->path = t; 323*4887Schin e->len = n; 324*4887Schin e++; 325*4887Schin } 326*4887Schin } 327*4887Schin while (*s == ':') 328*4887Schin s++; 329*4887Schin } while (*s && e < &std[elementsof(std)]); 330*4887Schin if (e < &std[elementsof(std)]) 331*4887Schin { 332*4887Schin e->len = strlen(e->path = "/usr/sbin"); 333*4887Schin if (++e < &std[elementsof(std)]) 334*4887Schin { 335*4887Schin e->len = strlen(e->path = "/sbin"); 336*4887Schin e++; 337*4887Schin } 338*4887Schin } 339*4887Schin if (s = getenv("PATH")) 340*4887Schin do 341*4887Schin { 342*4887Schin for (t = s; *s && *s != ':'; s++); 343*4887Schin if ((n = s - t) && *t == '/') 344*4887Schin { 345*4887Schin for (p = std; p < e; p++) 346*4887Schin if (p->len == n && !strncmp(t, p->path, n)) 347*4887Schin { 348*4887Schin sfsprintf(buf, sizeof(buf), "%-*.*s/%s", n, n, t, error_info.id); 349*4887Schin if (!access(buf, X_OK)) 350*4887Schin { 351*4887Schin cmd = buf; 352*4887Schin goto found; 353*4887Schin } 354*4887Schin } 355*4887Schin } 356*4887Schin while (*s == ':') 357*4887Schin s++; 358*4887Schin } while (*s); 359*4887Schin 360*4887Schin /* 361*4887Schin * defer to the first getconf on the standard PATH 362*4887Schin */ 363*4887Schin 364*4887Schin for (p = std; p < e; p++) 365*4887Schin { 366*4887Schin sfsprintf(buf, sizeof(buf), "%-*.*s/%s", p->len, p->len, p->path, error_info.id); 367*4887Schin if (!access(buf, X_OK)) 368*4887Schin { 369*4887Schin cmd = buf; 370*4887Schin goto found; 371*4887Schin } 372*4887Schin } 373*4887Schin 374*4887Schin /* 375*4887Schin * out of deferrals 376*4887Schin */ 377*4887Schin 378*4887Schin if (name) 379*4887Schin error(4, "%s: unknown name -- no native getconf(1) to defer to", name); 380*4887Schin else 381*4887Schin error(4, "no native getconf(1) to defer to"); 382*4887Schin return 2; 383*4887Schin 384*4887Schin found: 385*4887Schin 386*4887Schin /* 387*4887Schin * don't blame us for crappy diagnostics 388*4887Schin */ 389*4887Schin 390*4887Schin if ((n = procrun(cmd, oargv)) >= EXIT_NOEXEC) 391*4887Schin error(ERROR_SYSTEM|2, "%s: exec error [%d]", cmd, n); 392*4887Schin return n; 393*4887Schin } 394