xref: /titanic_41/usr/src/lib/libcmd/common/getconf.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
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