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