Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/getconf.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* Glenn Fowler
24
* AT&T Research
25
*
26
* getconf - get configuration values
27
*/
28
29
static const char usage[] =
30
"[-?\n@(#)$Id: getconf (AT&T Research) 2012-06-25 $\n]"
31
USAGE_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
"{"
109
"[+_AST_FEATURES?Process local writable values that are "
110
"different from the default are stored in the \b_AST_FEATURES\b "
111
"environment variable. The \b_AST_FEATURES\b value is a "
112
"space-separated list of \aname\a \apath\a \avalue\a 3-tuples, "
113
"where \aname\a is the system configuration name, \apath\a is "
114
"the corresponding path, \b-\b if no path is applicable, and "
115
"\avalue\a is the system configuration value. \b_AST_FEATURES\b "
116
"is an implementation detail of process inheritance; it may "
117
"change or vanish in the future; don't rely on it.]"
118
"}"
119
"[+SEE ALSO?\bpathchk\b(1), \bconfstr\b(2), \bpathconf\b(2),"
120
" \bsysconf\b(2), \bastgetconf\b(3)]"
121
;
122
123
#include <cmd.h>
124
#include <proc.h>
125
#include <ls.h>
126
127
typedef struct Path_s
128
{
129
const char* path;
130
int len;
131
} Path_t;
132
133
int
134
b_getconf(int argc, char** argv, Shbltin_t* context)
135
{
136
register char* name;
137
register char* path;
138
register char* value;
139
register const char* s;
140
register const char* t;
141
char* pattern;
142
char* native;
143
char* cmd;
144
Path_t* e;
145
Path_t* p;
146
int flags;
147
int n;
148
int i;
149
int m;
150
int q;
151
char** oargv;
152
char buf[PATH_MAX];
153
Path_t std[64];
154
struct stat st0;
155
struct stat st1;
156
157
static const char empty[] = "-";
158
static const Path_t equiv[] = { { "/bin", 4 }, { "/usr/bin", 8 } };
159
160
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
161
oargv = argv;
162
if (*(native = astconf("GETCONF", NiL, NiL)) != '/')
163
native = 0;
164
flags = 0;
165
name = 0;
166
pattern = 0;
167
for (;;)
168
{
169
switch (optget(argv, usage))
170
{
171
case 'a':
172
if (native)
173
goto defer;
174
continue;
175
case 'b':
176
flags |= ASTCONF_base;
177
continue;
178
case 'c':
179
flags |= ASTCONF_matchcall;
180
pattern = opt_info.arg;
181
continue;
182
case 'd':
183
flags |= ASTCONF_defined;
184
continue;
185
case 'l':
186
flags |= ASTCONF_lower;
187
continue;
188
case 'n':
189
flags |= ASTCONF_matchname;
190
pattern = opt_info.arg;
191
continue;
192
case 'p':
193
flags |= ASTCONF_parse;
194
continue;
195
case 'q':
196
flags |= ASTCONF_quote;
197
continue;
198
case 'r':
199
flags |= ASTCONF_read;
200
continue;
201
case 's':
202
flags |= ASTCONF_matchstandard;
203
pattern = opt_info.arg;
204
continue;
205
case 't':
206
flags |= ASTCONF_table;
207
continue;
208
case 'v':
209
if (native)
210
goto defer;
211
continue;
212
case 'w':
213
flags |= ASTCONF_write;
214
continue;
215
case ':':
216
if (native)
217
goto defer;
218
error(2, "%s", opt_info.arg);
219
break;
220
case '?':
221
error(ERROR_usage(2), "%s", opt_info.arg);
222
break;
223
}
224
break;
225
}
226
argv += opt_info.index;
227
if (!(name = *argv))
228
path = 0;
229
else if (streq(name, empty))
230
{
231
name = 0;
232
if (path = *++argv)
233
{
234
argv++;
235
if (streq(path, empty))
236
path = 0;
237
}
238
}
239
if (error_info.errors || !name && *argv)
240
error(ERROR_usage(2), "%s", optusage(NiL));
241
if (!name)
242
astconflist(sfstdout, path, flags, pattern);
243
else
244
{
245
if (native)
246
flags |= (ASTCONF_system|ASTCONF_error);
247
do
248
{
249
if (!(path = *++argv))
250
value = 0;
251
else
252
{
253
if (streq(path, empty))
254
{
255
path = 0;
256
flags = 0;
257
}
258
if ((value = *++argv) && (streq(value, empty)))
259
{
260
value = 0;
261
flags = 0;
262
}
263
}
264
s = astgetconf(name, path, value, flags, errorf);
265
if (error_info.errors)
266
break;
267
if (!s)
268
{
269
if (native)
270
goto defer;
271
error(2, "%s: unknown name", name);
272
break;
273
}
274
if (!value)
275
{
276
if (flags & ASTCONF_write)
277
{
278
sfputr(sfstdout, name, ' ');
279
sfputr(sfstdout, path ? path : empty, ' ');
280
}
281
sfputr(sfstdout, s, '\n');
282
}
283
} while (*argv && (name = *++argv));
284
}
285
return error_info.errors != 0;
286
287
defer:
288
289
/*
290
* defer to argv[0] if absolute and it exists
291
*/
292
293
if ((cmd = oargv[0]) && *cmd == '/' && !access(cmd, X_OK))
294
goto found;
295
296
/*
297
* defer to the first getconf on $PATH that is also on the standard PATH
298
*/
299
300
e = std;
301
s = astconf("PATH", NiL, NiL);
302
q = !stat(equiv[0].path, &st0) && !stat(equiv[1].path, &st1) && st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev;
303
m = 0;
304
do
305
{
306
for (t = s; *s && *s != ':'; s++);
307
if ((n = s - t) && *t == '/')
308
{
309
if (q)
310
for (i = 0; i < 2; i++)
311
if (n == equiv[i].len && !strncmp(t, equiv[i].path, n))
312
{
313
if (m & (i+1))
314
t = 0;
315
else
316
{
317
m |= (i+1);
318
if (!(m & (!i+1)))
319
{
320
m |= (!i+1);
321
e->path = t;
322
e->len = n;
323
e++;
324
if (e >= &std[elementsof(std)])
325
break;
326
t = equiv[!i].path;
327
n = equiv[!i].len;
328
}
329
}
330
}
331
if (t)
332
{
333
e->path = t;
334
e->len = n;
335
e++;
336
}
337
}
338
while (*s == ':')
339
s++;
340
} while (*s && e < &std[elementsof(std)]);
341
if (e < &std[elementsof(std)])
342
{
343
e->len = strlen(e->path = "/usr/sbin");
344
if (++e < &std[elementsof(std)])
345
{
346
e->len = strlen(e->path = "/sbin");
347
e++;
348
}
349
}
350
if (s = getenv("PATH"))
351
do
352
{
353
for (t = s; *s && *s != ':'; s++);
354
if ((n = s - t) && *t == '/')
355
{
356
for (p = std; p < e; p++)
357
if (p->len == n && !strncmp(t, p->path, n))
358
{
359
sfsprintf(buf, sizeof(buf), "%-*.*s/%s", n, n, t, error_info.id);
360
if (!access(buf, X_OK))
361
{
362
cmd = buf;
363
goto found;
364
}
365
}
366
}
367
while (*s == ':')
368
s++;
369
} while (*s);
370
371
/*
372
* defer to the first getconf on the standard PATH
373
*/
374
375
for (p = std; p < e; p++)
376
{
377
sfsprintf(buf, sizeof(buf), "%-*.*s/%s", p->len, p->len, p->path, error_info.id);
378
if (!access(buf, X_OK))
379
{
380
cmd = buf;
381
goto found;
382
}
383
}
384
385
/*
386
* out of deferrals
387
*/
388
389
if (name)
390
error(4, "%s: unknown name -- no native getconf(1) to defer to", name);
391
else
392
error(4, "no native getconf(1) to defer to");
393
return 2;
394
395
found:
396
397
/*
398
* don't blame us for crappy diagnostics
399
*/
400
401
oargv[0] = cmd;
402
if ((n = sh_run(context, argc, oargv)) >= EXIT_NOEXEC)
403
error(ERROR_SYSTEM|2, "%s: exec error [%d]", cmd, n);
404
return n;
405
}
406
407