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