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