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