xref: /onnv-gate/usr/src/lib/libcmd/common/getconf.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1992-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                                                                      *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin  * Glenn Fowler
244887Schin  * AT&T Research
254887Schin  *
264887Schin  * getconf - get configuration values
274887Schin  */
284887Schin 
294887Schin static const char usage[] =
308462SApril.Chin@Sun.COM "[-?\n@(#)$Id: getconf (AT&T Research) 2008-04-24 $\n]"
314887Schin USAGE_LICENSE
324887Schin "[+NAME?getconf - get configuration values]"
334887Schin "[+DESCRIPTION?\bgetconf\b displays the system configuration value for"
344887Schin "	\aname\a. If \aname\a is a filesystem specific variable then"
354887Schin "	the value is determined relative to \apath\a or the current"
364887Schin "	directory if \apath\a is omitted. If \avalue\a is specified then"
374887Schin "	\bgetconf\b attempts to change the process local value to \avalue\a."
384887Schin "	\b-\b may be used in place of \apath\a when it is not relevant."
398462SApril.Chin@Sun.COM "	If \apath\a is \b=\b then the the \avalue\a is cached and used"
408462SApril.Chin@Sun.COM "	for subsequent tests in the calling and all child processes."
414887Schin "	Only \bwritable\b variables may be set; \breadonly\b variables"
424887Schin "	cannot be changed.]"
434887Schin "[+?The current value for \aname\a is written to the standard output. If"
444887Schin "	\aname\a is valid but undefined then \bundefined\b is written to"
454887Schin "	the standard output. If \aname\a is invalid or an error occurs in"
464887Schin "	determining its value, then a diagnostic written to the standard error"
474887Schin "	and \bgetconf\b exits with a non-zero exit status.]"
484887Schin "[+?More than one variable may be set or queried by providing the \aname\a"
494887Schin "	\apath\a \avalue\a 3-tuple for each variable, specifying \b-\b for"
504887Schin "	\avalue\a when querying.]"
514887Schin "[+?If no operands are specified then all known variables are written in"
524887Schin "	\aname\a=\avalue\a form to the standard output, one per line."
534887Schin "	Only one of \b--call\b, \b--name\b or \b--standard\b may be specified.]"
544887Schin "[+?This implementation uses the \bastgetconf\b(3) string interface to the native"
554887Schin "	\bsysconf\b(2), \bconfstr\b(2), \bpathconf\b(2), and \bsysinfo\b(2)"
564887Schin "	system calls. If \bgetconf\b on \b$PATH\b is not the default native"
574887Schin "	\bgetconf\b, named by \b$(getconf GETCONF)\b, then \bastgetconf\b(3)"
584887Schin "	checks only \bast\b specific extensions and the native system calls;"
594887Schin "	invalid options and/or names not supported by \bastgetconf\b(3) cause"
604887Schin "	the \bgetconf\b on \b$PATH\b to be executed.]"
614887Schin 
624887Schin "[a:all?Call the native \bgetconf\b(1) with option \b-a\b.]"
634887Schin "[b:base?List base variable name sans call and standard prefixes.]"
644887Schin "[c:call?Display variables with call prefix that matches \aRE\a. The call"
654887Schin "	prefixes are:]:[RE]{"
664887Schin "		[+CS?\bconfstr\b(2)]"
674887Schin "		[+PC?\bpathconf\b(2)]"
684887Schin "		[+SC?\bsysconf\b(2)]"
694887Schin "		[+SI?\bsysinfo\b(2)]"
704887Schin "		[+XX?Constant value.]"
714887Schin "}"
724887Schin "[d:defined?Only display defined values when no operands are specified.]"
734887Schin "[l:lowercase?List variable names in lower case.]"
744887Schin "[n:name?Display variables with name that match \aRE\a.]:[RE]"
754887Schin "[p:portable?Display the named \bwritable\b variables and values in a form that"
764887Schin "	can be directly executed by \bsh\b(1) to set the values. If \aname\a"
774887Schin "	is omitted then all \bwritable\b variables are listed.]"
784887Schin "[q:quote?\"...\" quote values.]"
794887Schin "[r:readonly?Display the named \breadonly\b variables in \aname\a=\avalue\a form."
804887Schin "	If \aname\a is omitted then all \breadonly\b variables are listed.]"
814887Schin "[s:standard?Display variables with standard prefix that matches \aRE\a."
824887Schin "	Use the \b--table\b option to view all standard prefixes, including"
834887Schin "	local additions. The standard prefixes available on all systems"
844887Schin "	are:]:[RE]{"
854887Schin "		[+AES]"
864887Schin "		[+AST]"
874887Schin "		[+C]"
884887Schin "		[+GNU]"
894887Schin "		[+POSIX]"
904887Schin "		[+SVID]"
914887Schin "		[+XBS5]"
924887Schin "		[+XOPEN]"
934887Schin "		[+XPG]"
944887Schin "}"
954887Schin "[t:table?Display the internal table that contains the name, standard,"
964887Schin "	standard section, and system call symbol prefix for each variable.]"
974887Schin "[w:writable?Display the named \bwritable\b variables in \aname\a=\avalue\a"
984887Schin "	form. If \aname\a is omitted then all \bwritable\b variables are"
994887Schin "	listed.]"
1004887Schin "[v:specification?Call the native \bgetconf\b(1) with option"
1014887Schin "	\b-v\b \aname\a.]:[name]"
1024887Schin 
1034887Schin "\n"
1044887Schin "\n[ name [ path [ value ] ] ... ]\n"
1054887Schin "\n"
1064887Schin 
1074887Schin "[+ENVIRONMENT]{"
1084887Schin "	[+_AST_FEATURES?Process local writable values that are different from"
1094887Schin "		the default are stored in the \b_AST_FEATURES\b environment"
1104887Schin "		variable. The \b_AST_FEATURES\b value is a space-separated"
1114887Schin "		list of \aname\a \apath\a \avalue\a 3-tuples, where"
1124887Schin "		\aname\a is the system configuration name, \apath\a is the"
1134887Schin "		corresponding path, \b-\b if no path is applicable, and"
1144887Schin "		\avalue\a is the system configuration value.]"
1154887Schin "}"
1164887Schin "[+SEE ALSO?\bpathchk\b(1), \bconfstr\b(2), \bpathconf\b(2),"
1174887Schin "	\bsysconf\b(2), \bastgetconf\b(3)]"
1184887Schin ;
1194887Schin 
1204887Schin #include <cmd.h>
1214887Schin #include <proc.h>
1224887Schin #include <ls.h>
1234887Schin 
1244887Schin typedef struct Path_s
1254887Schin {
1268462SApril.Chin@Sun.COM 	const char*	path;
1274887Schin 	int		len;
1284887Schin } Path_t;
1294887Schin 
1304887Schin int
b_getconf(int argc,char ** argv,void * context)1314887Schin b_getconf(int argc, char** argv, void* context)
1324887Schin {
1334887Schin 	register char*		name;
1344887Schin 	register char*		path;
1354887Schin 	register char*		value;
1368462SApril.Chin@Sun.COM 	register const char*	s;
1378462SApril.Chin@Sun.COM 	register const char*	t;
1384887Schin 	char*			pattern;
1394887Schin 	char*			native;
1404887Schin 	char*			cmd;
1414887Schin 	Path_t*			e;
1424887Schin 	Path_t*			p;
1434887Schin 	int			flags;
1444887Schin 	int			n;
1454887Schin 	int			i;
1464887Schin 	int			m;
1474887Schin 	int			q;
1484887Schin 	char**			oargv;
1494887Schin 	char			buf[PATH_MAX];
1504887Schin 	Path_t			std[64];
1514887Schin 	struct stat		st0;
1524887Schin 	struct stat		st1;
1534887Schin 
1544887Schin 	static const char	empty[] = "-";
1554887Schin 	static const Path_t	equiv[] = { { "/bin", 4 }, { "/usr/bin", 8 } };
1564887Schin 
1574887Schin 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
1584887Schin 	oargv = argv;
1594887Schin 	if (*(native = astconf("GETCONF", NiL, NiL)) != '/')
1604887Schin 		native = 0;
1614887Schin 	flags = 0;
1624887Schin 	name = 0;
1634887Schin 	pattern = 0;
1644887Schin 	for (;;)
1654887Schin 	{
1664887Schin 		switch (optget(argv, usage))
1674887Schin 		{
1684887Schin 		case 'a':
1694887Schin 			if (native)
1704887Schin 				goto defer;
1714887Schin 			continue;
1724887Schin 		case 'b':
1734887Schin 			flags |= ASTCONF_base;
1744887Schin 			continue;
1754887Schin 		case 'c':
1764887Schin 			flags |= ASTCONF_matchcall;
1774887Schin 			pattern = opt_info.arg;
1784887Schin 			continue;
1794887Schin 		case 'd':
1804887Schin 			flags |= ASTCONF_defined;
1814887Schin 			continue;
1824887Schin 		case 'l':
1834887Schin 			flags |= ASTCONF_lower;
1844887Schin 			continue;
1854887Schin 		case 'n':
1864887Schin 			flags |= ASTCONF_matchname;
1874887Schin 			pattern = opt_info.arg;
1884887Schin 			continue;
1894887Schin 		case 'p':
1904887Schin 			flags |= ASTCONF_parse;
1914887Schin 			continue;
1924887Schin 		case 'q':
1934887Schin 			flags |= ASTCONF_quote;
1944887Schin 			continue;
1954887Schin 		case 'r':
1964887Schin 			flags |= ASTCONF_read;
1974887Schin 			continue;
1984887Schin 		case 's':
1994887Schin 			flags |= ASTCONF_matchstandard;
2004887Schin 			pattern = opt_info.arg;
2014887Schin 			continue;
2024887Schin 		case 't':
2034887Schin 			flags |= ASTCONF_table;
2044887Schin 			continue;
2054887Schin 		case 'v':
2064887Schin 			if (native)
2074887Schin 				goto defer;
2084887Schin 			continue;
2094887Schin 		case 'w':
2104887Schin 			flags |= ASTCONF_write;
2114887Schin 			continue;
2124887Schin 		case ':':
2134887Schin 			if (native)
2144887Schin 				goto defer;
2154887Schin 			error(2, "%s", opt_info.arg);
2164887Schin 			break;
2174887Schin 		case '?':
2184887Schin 			error(ERROR_usage(2), "%s", opt_info.arg);
2194887Schin 			break;
2204887Schin 		}
2214887Schin 		break;
2224887Schin 	}
2234887Schin 	argv += opt_info.index;
2244887Schin 	if (!(name = *argv))
2254887Schin 		path = 0;
2264887Schin 	else if (streq(name, empty))
2274887Schin 	{
2284887Schin 		name = 0;
2294887Schin 		if (path = *++argv)
2304887Schin 		{
2314887Schin 			argv++;
2324887Schin 			if (streq(path, empty))
2334887Schin 				path = 0;
2344887Schin 		}
2354887Schin 	}
2364887Schin 	if (error_info.errors || !name && *argv)
2374887Schin 		error(ERROR_usage(2), "%s", optusage(NiL));
2384887Schin 	if (!name)
2394887Schin 		astconflist(sfstdout, path, flags, pattern);
2404887Schin 	else
2414887Schin 	{
2424887Schin 		flags = native ? (ASTCONF_system|ASTCONF_error) : 0;
2434887Schin 		do
2444887Schin 		{
2454887Schin 			if (!(path = *++argv))
2464887Schin 				value = 0;
2474887Schin 			else
2484887Schin 			{
2494887Schin 				if (streq(path, empty))
2504887Schin 				{
2514887Schin 					path = 0;
2524887Schin 					flags = 0;
2534887Schin 				}
2544887Schin 				if ((value = *++argv) && (streq(value, empty)))
2554887Schin 				{
2564887Schin 					value = 0;
2574887Schin 					flags = 0;
2584887Schin 				}
2594887Schin 			}
2604887Schin 			s = astgetconf(name, path, value, flags, errorf);
2614887Schin 			if (error_info.errors)
2624887Schin 				break;
2634887Schin 			if (!s)
2644887Schin 				goto defer;
2654887Schin 			if (!value)
2664887Schin 			{
2674887Schin 				if (flags & ASTCONF_write)
2684887Schin 				{
2694887Schin 					sfputr(sfstdout, name, ' ');
2704887Schin 					sfputr(sfstdout, path ? path : empty, ' ');
2714887Schin 				}
2724887Schin 				sfputr(sfstdout, s, '\n');
2734887Schin 			}
2744887Schin 		} while (*argv && (name = *++argv));
2754887Schin 	}
2764887Schin 	return error_info.errors != 0;
2774887Schin 
2784887Schin  defer:
2794887Schin 
2804887Schin 	/*
2814887Schin 	 * defer to argv[0] if absolute and it exists
2824887Schin 	 */
2834887Schin 
2844887Schin 	if ((cmd = oargv[0]) && *cmd == '/' && !access(cmd, X_OK))
2854887Schin 		goto found;
2864887Schin 
2874887Schin 	/*
2884887Schin 	 * defer to the first getconf on $PATH that is also on the standard PATH
2894887Schin 	 */
2904887Schin 
2914887Schin 	e = std;
2924887Schin 	s = astconf("PATH", NiL, NiL);
2934887Schin 	q = !stat(equiv[0].path, &st0) && !stat(equiv[1].path, &st1) && st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev;
2944887Schin 	m = 0;
2954887Schin 	do
2964887Schin 	{
2974887Schin 		for (t = s; *s && *s != ':'; s++);
2984887Schin 		if ((n = s - t) && *t == '/')
2994887Schin 		{
3004887Schin 			if (q)
3014887Schin 				for (i = 0; i < 2; i++)
3024887Schin 					if (n == equiv[i].len && !strncmp(t, equiv[i].path, n))
3034887Schin 					{
3044887Schin 						if (m & (i+1))
3054887Schin 							t = 0;
3064887Schin 						else
3074887Schin 						{
3084887Schin 							m |= (i+1);
3094887Schin 							if (!(m & (!i+1)))
3104887Schin 							{
3114887Schin 								m |= (!i+1);
3124887Schin 								e->path = t;
3134887Schin 								e->len = n;
3144887Schin 								e++;
3154887Schin 								if (e >= &std[elementsof(std)])
3164887Schin 									break;
3174887Schin 								t = equiv[!i].path;
3184887Schin 								n = equiv[!i].len;
3194887Schin 							}
3204887Schin 						}
3214887Schin 					}
3224887Schin 			if (t)
3234887Schin 			{
3244887Schin 				e->path = t;
3254887Schin 				e->len = n;
3264887Schin 				e++;
3274887Schin 			}
3284887Schin 		}
3294887Schin 		while (*s == ':')
3304887Schin 			s++;
3314887Schin 	} while (*s && e < &std[elementsof(std)]);
3324887Schin 	if (e < &std[elementsof(std)])
3334887Schin 	{
3344887Schin 		e->len = strlen(e->path = "/usr/sbin");
3354887Schin 		if (++e < &std[elementsof(std)])
3364887Schin 		{
3374887Schin 			e->len = strlen(e->path = "/sbin");
3384887Schin 			e++;
3394887Schin 		}
3404887Schin 	}
3414887Schin 	if (s = getenv("PATH"))
3424887Schin 		do
3434887Schin 		{
3444887Schin 			for (t = s; *s && *s != ':'; s++);
3454887Schin 			if ((n = s - t) && *t == '/')
3464887Schin 			{
3474887Schin 				for (p = std; p < e; p++)
3484887Schin 					if (p->len == n && !strncmp(t, p->path, n))
3494887Schin 					{
3504887Schin 						sfsprintf(buf, sizeof(buf), "%-*.*s/%s", n, n, t, error_info.id);
3514887Schin 						if (!access(buf, X_OK))
3524887Schin 						{
3534887Schin 							cmd = buf;
3544887Schin 							goto found;
3554887Schin 						}
3564887Schin 					}
3574887Schin 			}
3584887Schin 			while (*s == ':')
3594887Schin 				s++;
3604887Schin 		} while (*s);
3614887Schin 
3624887Schin 	/*
3634887Schin 	 * defer to the first getconf on the standard PATH
3644887Schin 	 */
3654887Schin 
3664887Schin 	for (p = std; p < e; p++)
3674887Schin 	{
3684887Schin 		sfsprintf(buf, sizeof(buf), "%-*.*s/%s", p->len, p->len, p->path, error_info.id);
3694887Schin 		if (!access(buf, X_OK))
3704887Schin 		{
3714887Schin 			cmd = buf;
3724887Schin 			goto found;
3734887Schin 		}
3744887Schin 	}
3754887Schin 
3764887Schin 	/*
3774887Schin 	 * out of deferrals
3784887Schin 	 */
3794887Schin 
3804887Schin 	if (name)
3814887Schin 		error(4, "%s: unknown name -- no native getconf(1) to defer to", name);
3824887Schin 	else
3834887Schin 		error(4, "no native getconf(1) to defer to");
3844887Schin 	return 2;
3854887Schin 
3864887Schin  found:
3874887Schin 
3884887Schin 	/*
3894887Schin 	 * don't blame us for crappy diagnostics
3904887Schin 	 */
3914887Schin 
3928462SApril.Chin@Sun.COM 	oargv[0] = cmd;
3938462SApril.Chin@Sun.COM 	if ((n = sh_run(context, argc, oargv)) >= EXIT_NOEXEC)
3944887Schin 		error(ERROR_SYSTEM|2, "%s: exec error [%d]", cmd, n);
3954887Schin 	return n;
3964887Schin }
397