xref: /titanic_53/usr/src/cmd/power/parse.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "pmconfig.h"
30*7c478bd9Sstevel@tonic-gate #include <deflt.h>
31*7c478bd9Sstevel@tonic-gate #include <pwd.h>
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #ifdef sparc
34*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
35*7c478bd9Sstevel@tonic-gate static char sf_cmt[] = "# Statefile\t\tPath\n";
36*7c478bd9Sstevel@tonic-gate #endif
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate static char as_cmt[] =
39*7c478bd9Sstevel@tonic-gate 	"# Auto-Shutdown\t\tIdle(min)\tStart/Finish(hh:mm)\tBehavior\n";
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate char **line_args;
42*7c478bd9Sstevel@tonic-gate int lineno = 0;
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * cpr and pm combined permission/update status
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate prmup_t cpr_status = { 0, OKUP, "cpr" };
48*7c478bd9Sstevel@tonic-gate prmup_t pm_status  = { 0, OKUP, "pm" };
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * For config file parsing to work correctly/efficiently, this table
53*7c478bd9Sstevel@tonic-gate  * needs to be sorted by .keyword and any longer string like "device"
54*7c478bd9Sstevel@tonic-gate  * must appear before a substring like "dev".
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate static cinfo_t conftab[] = {
57*7c478bd9Sstevel@tonic-gate 	"autopm",		autopm,  &pm_status,	NULL,	2, 0, 1,
58*7c478bd9Sstevel@tonic-gate 	"autoshutdown",		autosd,  &cpr_status,	as_cmt,	5, 0, 1,
59*7c478bd9Sstevel@tonic-gate 	"device-dependency-property",
60*7c478bd9Sstevel@tonic-gate 				ddprop,  &pm_status,	NULL,	3, 1, 1,
61*7c478bd9Sstevel@tonic-gate 	"device-dependency",	devdep,  &pm_status,	NULL,	3, 1, 1,
62*7c478bd9Sstevel@tonic-gate 	"device-thresholds",	devthr,  &pm_status,	NULL,	3, 1, 1,
63*7c478bd9Sstevel@tonic-gate 	"diskreads",		dreads,  &cpr_status,	NULL,	2, 0, 1,
64*7c478bd9Sstevel@tonic-gate 	"idlecheck",		idlechk, &cpr_status,	NULL,	2, 0, 0,
65*7c478bd9Sstevel@tonic-gate 	"loadaverage",		loadavg, &cpr_status,	NULL,	2, 0, 1,
66*7c478bd9Sstevel@tonic-gate 	"nfsreqs",		nfsreq,  &cpr_status,	NULL,	2, 0, 1,
67*7c478bd9Sstevel@tonic-gate #ifdef  sparc
68*7c478bd9Sstevel@tonic-gate 	"statefile",		sfpath,  &cpr_status,	sf_cmt,	2, 0, 0,
69*7c478bd9Sstevel@tonic-gate #endif
70*7c478bd9Sstevel@tonic-gate 	"system-threshold",	systhr,  &pm_status,	NULL,	2, 0, 1,
71*7c478bd9Sstevel@tonic-gate 	"ttychars",		tchars,  &cpr_status,	NULL,	2, 0, 1,
72*7c478bd9Sstevel@tonic-gate 	NULL,			NULL,	 NULL,		NULL,	0, 0, 0,
73*7c478bd9Sstevel@tonic-gate };
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * Set cpr/pm permission from default file info.
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate static void
80*7c478bd9Sstevel@tonic-gate set_perm(char *defstr, char *user, int *perm, int cons)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	char *dinfo, *tk;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	/*
85*7c478bd9Sstevel@tonic-gate 	 * /etc/default/power entries are:
86*7c478bd9Sstevel@tonic-gate 	 *	all			(all users + root)
87*7c478bd9Sstevel@tonic-gate 	 *	-			(none + root)
88*7c478bd9Sstevel@tonic-gate 	 *	<user1[, user2...>	(list users + root)
89*7c478bd9Sstevel@tonic-gate 	 *	console-owner		(console onwer + root)
90*7c478bd9Sstevel@tonic-gate 	 * Any error in reading/parsing the file limits the
91*7c478bd9Sstevel@tonic-gate 	 * access requirement to root.
92*7c478bd9Sstevel@tonic-gate 	 */
93*7c478bd9Sstevel@tonic-gate 	dinfo = defread(defstr);
94*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "set_perm: \"%s\", value \"%s\"\n",
95*7c478bd9Sstevel@tonic-gate 	    defstr, dinfo ? dinfo : "NULL");
96*7c478bd9Sstevel@tonic-gate 	if (dinfo == NULL)
97*7c478bd9Sstevel@tonic-gate 		return;
98*7c478bd9Sstevel@tonic-gate 	else if (strcmp(dinfo, "all") == 0)
99*7c478bd9Sstevel@tonic-gate 		*perm = 1;
100*7c478bd9Sstevel@tonic-gate 	else if (strcmp(dinfo, "console-owner") == 0)
101*7c478bd9Sstevel@tonic-gate 		*perm = cons;
102*7c478bd9Sstevel@tonic-gate 	else if (user != NULL &&
103*7c478bd9Sstevel@tonic-gate 	    (*dinfo == '<') && (tk = strrchr(++dinfo, '>'))) {
104*7c478bd9Sstevel@tonic-gate 		/* Scan dinfo for a matching user. */
105*7c478bd9Sstevel@tonic-gate 		for (*tk = '\0'; tk = strtok(dinfo, ", "); dinfo = NULL) {
106*7c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "match_user: cmp (\"%s\", \"%s\")\n",
107*7c478bd9Sstevel@tonic-gate 			    tk, user);
108*7c478bd9Sstevel@tonic-gate 			if (strcmp(tk, user) == 0) {
109*7c478bd9Sstevel@tonic-gate 				*perm = 1;
110*7c478bd9Sstevel@tonic-gate 				break;
111*7c478bd9Sstevel@tonic-gate 			}
112*7c478bd9Sstevel@tonic-gate 		}
113*7c478bd9Sstevel@tonic-gate 	}
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  * Lookup cpr/pm user permissions in "/etc/default/power".
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate void
121*7c478bd9Sstevel@tonic-gate lookup_perms(void)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	struct passwd *pent;
124*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
125*7c478bd9Sstevel@tonic-gate 	int cons_perm;
126*7c478bd9Sstevel@tonic-gate 	char *user;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if ((ruid = getuid()) == 0) {
129*7c478bd9Sstevel@tonic-gate 		cpr_status.perm = pm_status.perm = 1;
130*7c478bd9Sstevel@tonic-gate 		return;
131*7c478bd9Sstevel@tonic-gate 	} else if ((pent = getpwuid(ruid)) != NULL) {
132*7c478bd9Sstevel@tonic-gate 		user = pent->pw_name;
133*7c478bd9Sstevel@tonic-gate 	} else {
134*7c478bd9Sstevel@tonic-gate 		user = NULL;
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	if (defopen("/etc/default/power") == -1)
138*7c478bd9Sstevel@tonic-gate 		return;
139*7c478bd9Sstevel@tonic-gate 	if (stat("/dev/console", &stbuf) == -1)
140*7c478bd9Sstevel@tonic-gate 		cons_perm = 0;
141*7c478bd9Sstevel@tonic-gate 	else
142*7c478bd9Sstevel@tonic-gate 		cons_perm = (ruid == stbuf.st_uid);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	set_perm("PMCHANGEPERM=", user, &pm_status.perm, cons_perm);
145*7c478bd9Sstevel@tonic-gate 	set_perm("CPRCHANGEPERM=", user, &cpr_status.perm, cons_perm);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	(void) defopen(NULL);
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate #ifdef sparc
152*7c478bd9Sstevel@tonic-gate /*
153*7c478bd9Sstevel@tonic-gate  * Lookup energystar-v[23] property and set estar_vers.
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate void
156*7c478bd9Sstevel@tonic-gate lookup_estar_vers(void)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	char es_prop[] = "energystar-v?", *fmt = "%s init/access error\n";
159*7c478bd9Sstevel@tonic-gate 	di_prom_handle_t ph;
160*7c478bd9Sstevel@tonic-gate 	di_node_t node;
161*7c478bd9Sstevel@tonic-gate 	uchar_t *prop_data;
162*7c478bd9Sstevel@tonic-gate 	int last;
163*7c478bd9Sstevel@tonic-gate 	char ch;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if ((node = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
166*7c478bd9Sstevel@tonic-gate 		mesg(MERR, fmt, "di_init");
167*7c478bd9Sstevel@tonic-gate 		return;
168*7c478bd9Sstevel@tonic-gate 	} else if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
169*7c478bd9Sstevel@tonic-gate 		mesg(MERR, fmt, "di_prom_init");
170*7c478bd9Sstevel@tonic-gate 		di_fini(node);
171*7c478bd9Sstevel@tonic-gate 		return;
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 	last = strlen(es_prop) - 1;
174*7c478bd9Sstevel@tonic-gate 	for (ch = ESTAR_V2; ch <= ESTAR_V3; ch++) {
175*7c478bd9Sstevel@tonic-gate 		es_prop[last] = ch;
176*7c478bd9Sstevel@tonic-gate 		if (di_prom_prop_lookup_bytes(ph, node,
177*7c478bd9Sstevel@tonic-gate 		    es_prop, &prop_data) == 0) {
178*7c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "get_estar_vers: %s prop found\n",
179*7c478bd9Sstevel@tonic-gate 			    es_prop);
180*7c478bd9Sstevel@tonic-gate 			estar_vers = ch;
181*7c478bd9Sstevel@tonic-gate 			break;
182*7c478bd9Sstevel@tonic-gate 		}
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 	di_prom_fini(ph);
185*7c478bd9Sstevel@tonic-gate 	di_fini(node);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate #endif /* sparc */
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate  * limit open() to the real user
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate static int
194*7c478bd9Sstevel@tonic-gate pmc_open(char *name, int oflag)
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	uid_t euid;
197*7c478bd9Sstevel@tonic-gate 	int fd;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	euid = geteuid();
200*7c478bd9Sstevel@tonic-gate 	if (seteuid(ruid) == -1)
201*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot reset euid to %d, %s\n",
202*7c478bd9Sstevel@tonic-gate 		    ruid, strerror(errno));
203*7c478bd9Sstevel@tonic-gate 	fd = open(name, oflag);
204*7c478bd9Sstevel@tonic-gate 	(void) seteuid(euid);
205*7c478bd9Sstevel@tonic-gate 	return (fd);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate /*
210*7c478bd9Sstevel@tonic-gate  * Alloc space and read a config file; caller needs to free the space.
211*7c478bd9Sstevel@tonic-gate  */
212*7c478bd9Sstevel@tonic-gate static char *
213*7c478bd9Sstevel@tonic-gate get_conf_data(char *name)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
216*7c478bd9Sstevel@tonic-gate 	ssize_t nread;
217*7c478bd9Sstevel@tonic-gate 	size_t size;
218*7c478bd9Sstevel@tonic-gate 	char *buf;
219*7c478bd9Sstevel@tonic-gate 	int fd;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	if ((fd = pmc_open(name, O_RDONLY)) == -1)
222*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot open %s\n", name);
223*7c478bd9Sstevel@tonic-gate 	else if (fstat(fd, &stbuf) == -1)
224*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot stat %s\n", name);
225*7c478bd9Sstevel@tonic-gate 	size = (size_t)stbuf.st_size;
226*7c478bd9Sstevel@tonic-gate 	def_src = (stbuf.st_ino == def_info.st_ino &&
227*7c478bd9Sstevel@tonic-gate 	    stbuf.st_dev == def_info.st_dev);
228*7c478bd9Sstevel@tonic-gate 	if ((buf = malloc(size + 1)) == NULL)
229*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot allocate %u for \"%s\"\n", size + 1, name);
230*7c478bd9Sstevel@tonic-gate 	nread = read(fd, buf, size);
231*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
232*7c478bd9Sstevel@tonic-gate 	if (nread != (ssize_t)size)
233*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "read error, expect %u, got %d, file \"%s\"\n",
234*7c478bd9Sstevel@tonic-gate 		    size, nread, name);
235*7c478bd9Sstevel@tonic-gate 	*(buf + size) = '\0';
236*7c478bd9Sstevel@tonic-gate 	return (buf);
237*7c478bd9Sstevel@tonic-gate }
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate /*
241*7c478bd9Sstevel@tonic-gate  * Add an arg to line_args, adding space if needed.
242*7c478bd9Sstevel@tonic-gate  */
243*7c478bd9Sstevel@tonic-gate static void
244*7c478bd9Sstevel@tonic-gate newarg(char *arg, int index)
245*7c478bd9Sstevel@tonic-gate {
246*7c478bd9Sstevel@tonic-gate 	static int alcnt;
247*7c478bd9Sstevel@tonic-gate 	size_t size;
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	if ((index + 1) > alcnt) {
250*7c478bd9Sstevel@tonic-gate 		alcnt += 4;
251*7c478bd9Sstevel@tonic-gate 		size = alcnt * sizeof (*line_args);
252*7c478bd9Sstevel@tonic-gate 		if ((line_args = realloc(line_args, size)) == NULL)
253*7c478bd9Sstevel@tonic-gate 			mesg(MEXIT, "cannot alloc %u for line args\n", size);
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 	*(line_args + index) = arg;
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /*
260*7c478bd9Sstevel@tonic-gate  * Convert blank-delimited words into an arg vector and return
261*7c478bd9Sstevel@tonic-gate  * the arg count; character strings get null-terminated in place.
262*7c478bd9Sstevel@tonic-gate  */
263*7c478bd9Sstevel@tonic-gate static int
264*7c478bd9Sstevel@tonic-gate build_args(char *cline, char *tail)
265*7c478bd9Sstevel@tonic-gate {
266*7c478bd9Sstevel@tonic-gate 	extern int debug;
267*7c478bd9Sstevel@tonic-gate 	char **vec, *arg, *cp;
268*7c478bd9Sstevel@tonic-gate 	int cnt = 0;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	/*
271*7c478bd9Sstevel@tonic-gate 	 * Search logic: look for "\\\n" as a continuation marker,
272*7c478bd9Sstevel@tonic-gate 	 * treat any other "\\*" as ordinary arg data, scan until a
273*7c478bd9Sstevel@tonic-gate 	 * white-space delimiter is found, and if the arg has length,
274*7c478bd9Sstevel@tonic-gate 	 * null-terminate and save arg to line_args.  The scan includes
275*7c478bd9Sstevel@tonic-gate 	 * tail so the last arg is found without any special-case code.
276*7c478bd9Sstevel@tonic-gate 	 */
277*7c478bd9Sstevel@tonic-gate 	for (arg = cp = cline; cp <= tail; cp++) {
278*7c478bd9Sstevel@tonic-gate 		if (*cp == '\\') {
279*7c478bd9Sstevel@tonic-gate 			if (*(cp + 1) && *(cp + 1) != '\n') {
280*7c478bd9Sstevel@tonic-gate 				cp++;
281*7c478bd9Sstevel@tonic-gate 				continue;
282*7c478bd9Sstevel@tonic-gate 			}
283*7c478bd9Sstevel@tonic-gate 		} else if (strchr(" \t\n", *cp) == NULL)
284*7c478bd9Sstevel@tonic-gate 			continue;
285*7c478bd9Sstevel@tonic-gate 		if (cp - arg) {
286*7c478bd9Sstevel@tonic-gate 			*cp = '\0';
287*7c478bd9Sstevel@tonic-gate 			newarg(arg, cnt++);
288*7c478bd9Sstevel@tonic-gate 		}
289*7c478bd9Sstevel@tonic-gate 		arg = cp + 1;
290*7c478bd9Sstevel@tonic-gate 	}
291*7c478bd9Sstevel@tonic-gate 	newarg(NULL, cnt);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	if (debug) {
294*7c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\nline %d, found %d args:\n", lineno, cnt);
295*7c478bd9Sstevel@tonic-gate 		for (vec = line_args; *vec; vec++)
296*7c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "    \"%s\"\n", *vec);
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	return (cnt);
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate /*
304*7c478bd9Sstevel@tonic-gate  * Match leading keyword from a conf line and
305*7c478bd9Sstevel@tonic-gate  * return a reference to a config info struct.
306*7c478bd9Sstevel@tonic-gate  */
307*7c478bd9Sstevel@tonic-gate static cinfo_t *
308*7c478bd9Sstevel@tonic-gate get_cinfo(void)
309*7c478bd9Sstevel@tonic-gate {
310*7c478bd9Sstevel@tonic-gate 	cinfo_t *cip, *info = NULL;
311*7c478bd9Sstevel@tonic-gate 	char *keyword;
312*7c478bd9Sstevel@tonic-gate 	int chr_diff;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	/*
315*7c478bd9Sstevel@tonic-gate 	 * Scan the config table for a matching keyword; since the table
316*7c478bd9Sstevel@tonic-gate 	 * is sorted by keyword strings, a few optimizations can be done:
317*7c478bd9Sstevel@tonic-gate 	 * first compare only the first byte of the keyword, skip any
318*7c478bd9Sstevel@tonic-gate 	 * table string that starts with a lower ASCII value, compare the
319*7c478bd9Sstevel@tonic-gate 	 * full string only when the first byte matches, and stop checking
320*7c478bd9Sstevel@tonic-gate 	 * if the table string starts with a higher ASCII value.
321*7c478bd9Sstevel@tonic-gate 	 */
322*7c478bd9Sstevel@tonic-gate 	keyword = LINEARG(0);
323*7c478bd9Sstevel@tonic-gate 	for (cip = conftab; cip->keyword; cip++) {
324*7c478bd9Sstevel@tonic-gate 		chr_diff = (int)(*cip->keyword - *keyword);
325*7c478bd9Sstevel@tonic-gate #if 0
326*7c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "line %d, ('%c' - '%c') = %d\n",
327*7c478bd9Sstevel@tonic-gate 		    lineno, *cip->keyword, *line, chr_diff);
328*7c478bd9Sstevel@tonic-gate #endif
329*7c478bd9Sstevel@tonic-gate 		if (chr_diff < 0)
330*7c478bd9Sstevel@tonic-gate 			continue;
331*7c478bd9Sstevel@tonic-gate 		else if (chr_diff == 0) {
332*7c478bd9Sstevel@tonic-gate 			if (strcmp(keyword, cip->keyword) == 0) {
333*7c478bd9Sstevel@tonic-gate 				info = cip;
334*7c478bd9Sstevel@tonic-gate 				break;
335*7c478bd9Sstevel@tonic-gate 			}
336*7c478bd9Sstevel@tonic-gate 		} else
337*7c478bd9Sstevel@tonic-gate 			break;
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 	return (info);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate /*
344*7c478bd9Sstevel@tonic-gate  * Find the end of a [possibly continued] conf line
345*7c478bd9Sstevel@tonic-gate  * and record the real/lf-delimited line count at *lcnt.
346*7c478bd9Sstevel@tonic-gate  */
347*7c478bd9Sstevel@tonic-gate static char *
348*7c478bd9Sstevel@tonic-gate find_line_end(char *line, int *lcnt)
349*7c478bd9Sstevel@tonic-gate {
350*7c478bd9Sstevel@tonic-gate 	char *next, *lf;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	*lcnt = 0;
353*7c478bd9Sstevel@tonic-gate 	next = line;
354*7c478bd9Sstevel@tonic-gate 	while (lf = strchr(next, '\n')) {
355*7c478bd9Sstevel@tonic-gate 		(*lcnt)++;
356*7c478bd9Sstevel@tonic-gate 		if (lf == line || (*(lf - 1) != '\\') || *(lf + 1) == '\0')
357*7c478bd9Sstevel@tonic-gate 			break;
358*7c478bd9Sstevel@tonic-gate 		next = lf + 1;
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	return (lf);
361*7c478bd9Sstevel@tonic-gate }
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate /*
365*7c478bd9Sstevel@tonic-gate  * Parse the named conf file and for each conf line
366*7c478bd9Sstevel@tonic-gate  * call the action routine or conftab handler routine.
367*7c478bd9Sstevel@tonic-gate  */
368*7c478bd9Sstevel@tonic-gate void
369*7c478bd9Sstevel@tonic-gate parse_conf_file(char *name, vact_t action)
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate 	char *file_buf, *cline, *line, *lend;
372*7c478bd9Sstevel@tonic-gate 	cinfo_t *cip;
373*7c478bd9Sstevel@tonic-gate 	int linc, cnt;
374*7c478bd9Sstevel@tonic-gate 	size_t llen;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	file_buf = get_conf_data(name);
377*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "\nnow parsing \"%s\"...\n", name);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	lineno = 1;
380*7c478bd9Sstevel@tonic-gate 	line = file_buf;
381*7c478bd9Sstevel@tonic-gate 	while (lend = find_line_end(line, &linc)) {
382*7c478bd9Sstevel@tonic-gate 		/*
383*7c478bd9Sstevel@tonic-gate 		 * Each line should start with valid data
384*7c478bd9Sstevel@tonic-gate 		 * but leading white-space can be ignored
385*7c478bd9Sstevel@tonic-gate 		 */
386*7c478bd9Sstevel@tonic-gate 		while (line < lend) {
387*7c478bd9Sstevel@tonic-gate 			if (*line != ' ' && *line != '\t')
388*7c478bd9Sstevel@tonic-gate 				break;
389*7c478bd9Sstevel@tonic-gate 			line++;
390*7c478bd9Sstevel@tonic-gate 		}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 		/*
393*7c478bd9Sstevel@tonic-gate 		 * Copy line into allocated space and null-terminate
394*7c478bd9Sstevel@tonic-gate 		 * without the trailing line-feed.
395*7c478bd9Sstevel@tonic-gate 		 */
396*7c478bd9Sstevel@tonic-gate 		if ((llen = (lend - line)) != 0) {
397*7c478bd9Sstevel@tonic-gate 			if ((cline = malloc(llen + 1)) == NULL)
398*7c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "cannot alloc %u bytes "
399*7c478bd9Sstevel@tonic-gate 				    "for line copy\n", llen);
400*7c478bd9Sstevel@tonic-gate 			(void) memcpy(cline, line, llen);
401*7c478bd9Sstevel@tonic-gate 			*(cline + llen) = '\0';
402*7c478bd9Sstevel@tonic-gate 		} else
403*7c478bd9Sstevel@tonic-gate 			cline = NULL;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		/*
406*7c478bd9Sstevel@tonic-gate 		 * For blank and comment lines: possibly show a debug
407*7c478bd9Sstevel@tonic-gate 		 * message and otherwise ignore them.  For other lines:
408*7c478bd9Sstevel@tonic-gate 		 * parse into an arg vector and try to match the first
409*7c478bd9Sstevel@tonic-gate 		 * arg with conftab keywords.  When a match is found,
410*7c478bd9Sstevel@tonic-gate 		 * check for exact or minimum arg count, and call the
411*7c478bd9Sstevel@tonic-gate 		 * action or handler routine; if handler does not return
412*7c478bd9Sstevel@tonic-gate 		 * OKUP, set the referenced update value to NOUP so that
413*7c478bd9Sstevel@tonic-gate 		 * later CPR or PM updates are skipped.
414*7c478bd9Sstevel@tonic-gate 		 */
415*7c478bd9Sstevel@tonic-gate 		if (llen == 0)
416*7c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "\nline %d, blank...\n", lineno);
417*7c478bd9Sstevel@tonic-gate 		else if (*line == '#')
418*7c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "\nline %d, comment...\n", lineno);
419*7c478bd9Sstevel@tonic-gate 		else if (cnt = build_args(cline, cline + llen)) {
420*7c478bd9Sstevel@tonic-gate 			if ((cip = get_cinfo()) == NULL) {
421*7c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "unrecognized keyword \"%s\"\n",
422*7c478bd9Sstevel@tonic-gate 				    LINEARG(0));
423*7c478bd9Sstevel@tonic-gate 			} else if (cnt != cip->argc &&
424*7c478bd9Sstevel@tonic-gate 			    (cip->any == 0 || cnt < cip->argc)) {
425*7c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "found %d args, expect %d%s\n",
426*7c478bd9Sstevel@tonic-gate 				    cnt, cip->argc, cip->any ? "+" : "");
427*7c478bd9Sstevel@tonic-gate 			} else if (action)
428*7c478bd9Sstevel@tonic-gate 				(*action)(line, llen + 1, cip);
429*7c478bd9Sstevel@tonic-gate 			else if (cip->status->perm && (def_src || cip->alt)) {
430*7c478bd9Sstevel@tonic-gate 				if ((*cip->handler)() != OKUP)
431*7c478bd9Sstevel@tonic-gate 					cip->status->update = NOUP;
432*7c478bd9Sstevel@tonic-gate 			} else {
433*7c478bd9Sstevel@tonic-gate 				mesg(MDEBUG,
434*7c478bd9Sstevel@tonic-gate 				    "==> handler skipped: %s_perm %d, "
435*7c478bd9Sstevel@tonic-gate 				    "def_src %d, alt %d\n", cip->status->set,
436*7c478bd9Sstevel@tonic-gate 				    cip->status->perm, def_src, cip->alt);
437*7c478bd9Sstevel@tonic-gate 			}
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		if (cline)
441*7c478bd9Sstevel@tonic-gate 			free(cline);
442*7c478bd9Sstevel@tonic-gate 		line = lend + 1;
443*7c478bd9Sstevel@tonic-gate 		lineno += linc;
444*7c478bd9Sstevel@tonic-gate 	}
445*7c478bd9Sstevel@tonic-gate 	lineno = 0;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	free(file_buf);
448*7c478bd9Sstevel@tonic-gate }
449