xref: /illumos-gate/usr/src/cmd/power/parse.c (revision c42872d4489d6f0fbccfabe2a62f3c976ee1e5d6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*c42872d4Smh27603  * Common Development and Distribution License (the "License").
6*c42872d4Smh27603  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c42872d4Smh27603  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "pmconfig.h"
297c478bd9Sstevel@tonic-gate #include <deflt.h>
307c478bd9Sstevel@tonic-gate #include <pwd.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #ifdef sparc
337c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
347c478bd9Sstevel@tonic-gate static char sf_cmt[] = "# Statefile\t\tPath\n";
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static char as_cmt[] =
387c478bd9Sstevel@tonic-gate 	"# Auto-Shutdown\t\tIdle(min)\tStart/Finish(hh:mm)\tBehavior\n";
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate char **line_args;
417c478bd9Sstevel@tonic-gate int lineno = 0;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * cpr and pm combined permission/update status
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate prmup_t cpr_status = { 0, OKUP, "cpr" };
477c478bd9Sstevel@tonic-gate prmup_t pm_status  = { 0, OKUP, "pm" };
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * For config file parsing to work correctly/efficiently, this table
527c478bd9Sstevel@tonic-gate  * needs to be sorted by .keyword and any longer string like "device"
537c478bd9Sstevel@tonic-gate  * must appear before a substring like "dev".
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate static cinfo_t conftab[] = {
567c478bd9Sstevel@tonic-gate 	"autopm",		autopm,  &pm_status,	NULL,	2, 0, 1,
577c478bd9Sstevel@tonic-gate 	"autoshutdown",		autosd,  &cpr_status,	as_cmt,	5, 0, 1,
58*c42872d4Smh27603 	"cpu-threshold",	cputhr,  &pm_status,	NULL,	2, 0, 1,
59*c42872d4Smh27603 	"cpupm",		cpupm,   &pm_status,	NULL,	2, 0, 1,
607c478bd9Sstevel@tonic-gate 	"device-dependency-property",
617c478bd9Sstevel@tonic-gate 				ddprop,  &pm_status,	NULL,	3, 1, 1,
627c478bd9Sstevel@tonic-gate 	"device-dependency",	devdep,  &pm_status,	NULL,	3, 1, 1,
637c478bd9Sstevel@tonic-gate 	"device-thresholds",	devthr,  &pm_status,	NULL,	3, 1, 1,
647c478bd9Sstevel@tonic-gate 	"diskreads",		dreads,  &cpr_status,	NULL,	2, 0, 1,
657c478bd9Sstevel@tonic-gate 	"idlecheck",		idlechk, &cpr_status,	NULL,	2, 0, 0,
667c478bd9Sstevel@tonic-gate 	"loadaverage",		loadavg, &cpr_status,	NULL,	2, 0, 1,
677c478bd9Sstevel@tonic-gate 	"nfsreqs",		nfsreq,  &cpr_status,	NULL,	2, 0, 1,
687c478bd9Sstevel@tonic-gate #ifdef  sparc
697c478bd9Sstevel@tonic-gate 	"statefile",		sfpath,  &cpr_status,	sf_cmt,	2, 0, 0,
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate 	"system-threshold",	systhr,  &pm_status,	NULL,	2, 0, 1,
727c478bd9Sstevel@tonic-gate 	"ttychars",		tchars,  &cpr_status,	NULL,	2, 0, 1,
737c478bd9Sstevel@tonic-gate 	NULL,			NULL,	 NULL,		NULL,	0, 0, 0,
747c478bd9Sstevel@tonic-gate };
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * Set cpr/pm permission from default file info.
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate static void
817c478bd9Sstevel@tonic-gate set_perm(char *defstr, char *user, int *perm, int cons)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	char *dinfo, *tk;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	/*
867c478bd9Sstevel@tonic-gate 	 * /etc/default/power entries are:
877c478bd9Sstevel@tonic-gate 	 *	all			(all users + root)
887c478bd9Sstevel@tonic-gate 	 *	-			(none + root)
897c478bd9Sstevel@tonic-gate 	 *	<user1[, user2...>	(list users + root)
907c478bd9Sstevel@tonic-gate 	 *	console-owner		(console onwer + root)
917c478bd9Sstevel@tonic-gate 	 * Any error in reading/parsing the file limits the
927c478bd9Sstevel@tonic-gate 	 * access requirement to root.
937c478bd9Sstevel@tonic-gate 	 */
947c478bd9Sstevel@tonic-gate 	dinfo = defread(defstr);
957c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "set_perm: \"%s\", value \"%s\"\n",
967c478bd9Sstevel@tonic-gate 	    defstr, dinfo ? dinfo : "NULL");
977c478bd9Sstevel@tonic-gate 	if (dinfo == NULL)
987c478bd9Sstevel@tonic-gate 		return;
997c478bd9Sstevel@tonic-gate 	else if (strcmp(dinfo, "all") == 0)
1007c478bd9Sstevel@tonic-gate 		*perm = 1;
1017c478bd9Sstevel@tonic-gate 	else if (strcmp(dinfo, "console-owner") == 0)
1027c478bd9Sstevel@tonic-gate 		*perm = cons;
1037c478bd9Sstevel@tonic-gate 	else if (user != NULL &&
1047c478bd9Sstevel@tonic-gate 	    (*dinfo == '<') && (tk = strrchr(++dinfo, '>'))) {
1057c478bd9Sstevel@tonic-gate 		/* Scan dinfo for a matching user. */
1067c478bd9Sstevel@tonic-gate 		for (*tk = '\0'; tk = strtok(dinfo, ", "); dinfo = NULL) {
1077c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "match_user: cmp (\"%s\", \"%s\")\n",
1087c478bd9Sstevel@tonic-gate 			    tk, user);
1097c478bd9Sstevel@tonic-gate 			if (strcmp(tk, user) == 0) {
1107c478bd9Sstevel@tonic-gate 				*perm = 1;
1117c478bd9Sstevel@tonic-gate 				break;
1127c478bd9Sstevel@tonic-gate 			}
1137c478bd9Sstevel@tonic-gate 		}
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * Lookup cpr/pm user permissions in "/etc/default/power".
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate void
1227c478bd9Sstevel@tonic-gate lookup_perms(void)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	struct passwd *pent;
1257c478bd9Sstevel@tonic-gate 	struct stat stbuf;
1267c478bd9Sstevel@tonic-gate 	int cons_perm;
1277c478bd9Sstevel@tonic-gate 	char *user;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if ((ruid = getuid()) == 0) {
1307c478bd9Sstevel@tonic-gate 		cpr_status.perm = pm_status.perm = 1;
1317c478bd9Sstevel@tonic-gate 		return;
1327c478bd9Sstevel@tonic-gate 	} else if ((pent = getpwuid(ruid)) != NULL) {
1337c478bd9Sstevel@tonic-gate 		user = pent->pw_name;
1347c478bd9Sstevel@tonic-gate 	} else {
1357c478bd9Sstevel@tonic-gate 		user = NULL;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (defopen("/etc/default/power") == -1)
1397c478bd9Sstevel@tonic-gate 		return;
1407c478bd9Sstevel@tonic-gate 	if (stat("/dev/console", &stbuf) == -1)
1417c478bd9Sstevel@tonic-gate 		cons_perm = 0;
1427c478bd9Sstevel@tonic-gate 	else
1437c478bd9Sstevel@tonic-gate 		cons_perm = (ruid == stbuf.st_uid);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	set_perm("PMCHANGEPERM=", user, &pm_status.perm, cons_perm);
1467c478bd9Sstevel@tonic-gate 	set_perm("CPRCHANGEPERM=", user, &cpr_status.perm, cons_perm);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	(void) defopen(NULL);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate #ifdef sparc
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * Lookup energystar-v[23] property and set estar_vers.
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate void
1577c478bd9Sstevel@tonic-gate lookup_estar_vers(void)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	char es_prop[] = "energystar-v?", *fmt = "%s init/access error\n";
1607c478bd9Sstevel@tonic-gate 	di_prom_handle_t ph;
1617c478bd9Sstevel@tonic-gate 	di_node_t node;
1627c478bd9Sstevel@tonic-gate 	uchar_t *prop_data;
1637c478bd9Sstevel@tonic-gate 	int last;
1647c478bd9Sstevel@tonic-gate 	char ch;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if ((node = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
1677c478bd9Sstevel@tonic-gate 		mesg(MERR, fmt, "di_init");
1687c478bd9Sstevel@tonic-gate 		return;
1697c478bd9Sstevel@tonic-gate 	} else if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
1707c478bd9Sstevel@tonic-gate 		mesg(MERR, fmt, "di_prom_init");
1717c478bd9Sstevel@tonic-gate 		di_fini(node);
1727c478bd9Sstevel@tonic-gate 		return;
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 	last = strlen(es_prop) - 1;
1757c478bd9Sstevel@tonic-gate 	for (ch = ESTAR_V2; ch <= ESTAR_V3; ch++) {
1767c478bd9Sstevel@tonic-gate 		es_prop[last] = ch;
1777c478bd9Sstevel@tonic-gate 		if (di_prom_prop_lookup_bytes(ph, node,
1787c478bd9Sstevel@tonic-gate 		    es_prop, &prop_data) == 0) {
1797c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "get_estar_vers: %s prop found\n",
1807c478bd9Sstevel@tonic-gate 			    es_prop);
1817c478bd9Sstevel@tonic-gate 			estar_vers = ch;
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 		}
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 	di_prom_fini(ph);
1867c478bd9Sstevel@tonic-gate 	di_fini(node);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate #endif /* sparc */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate  * limit open() to the real user
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate static int
1957c478bd9Sstevel@tonic-gate pmc_open(char *name, int oflag)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	uid_t euid;
1987c478bd9Sstevel@tonic-gate 	int fd;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	euid = geteuid();
2017c478bd9Sstevel@tonic-gate 	if (seteuid(ruid) == -1)
2027c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot reset euid to %d, %s\n",
2037c478bd9Sstevel@tonic-gate 		    ruid, strerror(errno));
2047c478bd9Sstevel@tonic-gate 	fd = open(name, oflag);
2057c478bd9Sstevel@tonic-gate 	(void) seteuid(euid);
2067c478bd9Sstevel@tonic-gate 	return (fd);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate  * Alloc space and read a config file; caller needs to free the space.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate static char *
2147c478bd9Sstevel@tonic-gate get_conf_data(char *name)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	struct stat stbuf;
2177c478bd9Sstevel@tonic-gate 	ssize_t nread;
2187c478bd9Sstevel@tonic-gate 	size_t size;
2197c478bd9Sstevel@tonic-gate 	char *buf;
2207c478bd9Sstevel@tonic-gate 	int fd;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if ((fd = pmc_open(name, O_RDONLY)) == -1)
2237c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot open %s\n", name);
2247c478bd9Sstevel@tonic-gate 	else if (fstat(fd, &stbuf) == -1)
2257c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot stat %s\n", name);
2267c478bd9Sstevel@tonic-gate 	size = (size_t)stbuf.st_size;
2277c478bd9Sstevel@tonic-gate 	def_src = (stbuf.st_ino == def_info.st_ino &&
2287c478bd9Sstevel@tonic-gate 	    stbuf.st_dev == def_info.st_dev);
2297c478bd9Sstevel@tonic-gate 	if ((buf = malloc(size + 1)) == NULL)
2307c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot allocate %u for \"%s\"\n", size + 1, name);
2317c478bd9Sstevel@tonic-gate 	nread = read(fd, buf, size);
2327c478bd9Sstevel@tonic-gate 	(void) close(fd);
2337c478bd9Sstevel@tonic-gate 	if (nread != (ssize_t)size)
2347c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "read error, expect %u, got %d, file \"%s\"\n",
2357c478bd9Sstevel@tonic-gate 		    size, nread, name);
2367c478bd9Sstevel@tonic-gate 	*(buf + size) = '\0';
2377c478bd9Sstevel@tonic-gate 	return (buf);
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate  * Add an arg to line_args, adding space if needed.
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate static void
2457c478bd9Sstevel@tonic-gate newarg(char *arg, int index)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	static int alcnt;
2487c478bd9Sstevel@tonic-gate 	size_t size;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if ((index + 1) > alcnt) {
2517c478bd9Sstevel@tonic-gate 		alcnt += 4;
2527c478bd9Sstevel@tonic-gate 		size = alcnt * sizeof (*line_args);
2537c478bd9Sstevel@tonic-gate 		if ((line_args = realloc(line_args, size)) == NULL)
2547c478bd9Sstevel@tonic-gate 			mesg(MEXIT, "cannot alloc %u for line args\n", size);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 	*(line_args + index) = arg;
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate  * Convert blank-delimited words into an arg vector and return
2627c478bd9Sstevel@tonic-gate  * the arg count; character strings get null-terminated in place.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate static int
2657c478bd9Sstevel@tonic-gate build_args(char *cline, char *tail)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	extern int debug;
2687c478bd9Sstevel@tonic-gate 	char **vec, *arg, *cp;
2697c478bd9Sstevel@tonic-gate 	int cnt = 0;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/*
2727c478bd9Sstevel@tonic-gate 	 * Search logic: look for "\\\n" as a continuation marker,
2737c478bd9Sstevel@tonic-gate 	 * treat any other "\\*" as ordinary arg data, scan until a
2747c478bd9Sstevel@tonic-gate 	 * white-space delimiter is found, and if the arg has length,
2757c478bd9Sstevel@tonic-gate 	 * null-terminate and save arg to line_args.  The scan includes
2767c478bd9Sstevel@tonic-gate 	 * tail so the last arg is found without any special-case code.
2777c478bd9Sstevel@tonic-gate 	 */
2787c478bd9Sstevel@tonic-gate 	for (arg = cp = cline; cp <= tail; cp++) {
2797c478bd9Sstevel@tonic-gate 		if (*cp == '\\') {
2807c478bd9Sstevel@tonic-gate 			if (*(cp + 1) && *(cp + 1) != '\n') {
2817c478bd9Sstevel@tonic-gate 				cp++;
2827c478bd9Sstevel@tonic-gate 				continue;
2837c478bd9Sstevel@tonic-gate 			}
2847c478bd9Sstevel@tonic-gate 		} else if (strchr(" \t\n", *cp) == NULL)
2857c478bd9Sstevel@tonic-gate 			continue;
2867c478bd9Sstevel@tonic-gate 		if (cp - arg) {
2877c478bd9Sstevel@tonic-gate 			*cp = '\0';
2887c478bd9Sstevel@tonic-gate 			newarg(arg, cnt++);
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 		arg = cp + 1;
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	newarg(NULL, cnt);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (debug) {
2957c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\nline %d, found %d args:\n", lineno, cnt);
2967c478bd9Sstevel@tonic-gate 		for (vec = line_args; *vec; vec++)
2977c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "    \"%s\"\n", *vec);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	return (cnt);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * Match leading keyword from a conf line and
3067c478bd9Sstevel@tonic-gate  * return a reference to a config info struct.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate static cinfo_t *
3097c478bd9Sstevel@tonic-gate get_cinfo(void)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	cinfo_t *cip, *info = NULL;
3127c478bd9Sstevel@tonic-gate 	char *keyword;
3137c478bd9Sstevel@tonic-gate 	int chr_diff;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * Scan the config table for a matching keyword; since the table
3177c478bd9Sstevel@tonic-gate 	 * is sorted by keyword strings, a few optimizations can be done:
3187c478bd9Sstevel@tonic-gate 	 * first compare only the first byte of the keyword, skip any
3197c478bd9Sstevel@tonic-gate 	 * table string that starts with a lower ASCII value, compare the
3207c478bd9Sstevel@tonic-gate 	 * full string only when the first byte matches, and stop checking
3217c478bd9Sstevel@tonic-gate 	 * if the table string starts with a higher ASCII value.
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	keyword = LINEARG(0);
3247c478bd9Sstevel@tonic-gate 	for (cip = conftab; cip->keyword; cip++) {
3257c478bd9Sstevel@tonic-gate 		chr_diff = (int)(*cip->keyword - *keyword);
3267c478bd9Sstevel@tonic-gate #if 0
3277c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "line %d, ('%c' - '%c') = %d\n",
3287c478bd9Sstevel@tonic-gate 		    lineno, *cip->keyword, *line, chr_diff);
3297c478bd9Sstevel@tonic-gate #endif
3307c478bd9Sstevel@tonic-gate 		if (chr_diff < 0)
3317c478bd9Sstevel@tonic-gate 			continue;
3327c478bd9Sstevel@tonic-gate 		else if (chr_diff == 0) {
3337c478bd9Sstevel@tonic-gate 			if (strcmp(keyword, cip->keyword) == 0) {
3347c478bd9Sstevel@tonic-gate 				info = cip;
3357c478bd9Sstevel@tonic-gate 				break;
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 		} else
3387c478bd9Sstevel@tonic-gate 			break;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 	return (info);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate  * Find the end of a [possibly continued] conf line
3467c478bd9Sstevel@tonic-gate  * and record the real/lf-delimited line count at *lcnt.
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate static char *
3497c478bd9Sstevel@tonic-gate find_line_end(char *line, int *lcnt)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	char *next, *lf;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	*lcnt = 0;
3547c478bd9Sstevel@tonic-gate 	next = line;
3557c478bd9Sstevel@tonic-gate 	while (lf = strchr(next, '\n')) {
3567c478bd9Sstevel@tonic-gate 		(*lcnt)++;
3577c478bd9Sstevel@tonic-gate 		if (lf == line || (*(lf - 1) != '\\') || *(lf + 1) == '\0')
3587c478bd9Sstevel@tonic-gate 			break;
3597c478bd9Sstevel@tonic-gate 		next = lf + 1;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 	return (lf);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate  * Parse the named conf file and for each conf line
3677c478bd9Sstevel@tonic-gate  * call the action routine or conftab handler routine.
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate void
3707c478bd9Sstevel@tonic-gate parse_conf_file(char *name, vact_t action)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	char *file_buf, *cline, *line, *lend;
3737c478bd9Sstevel@tonic-gate 	cinfo_t *cip;
3747c478bd9Sstevel@tonic-gate 	int linc, cnt;
3757c478bd9Sstevel@tonic-gate 	size_t llen;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	file_buf = get_conf_data(name);
3787c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "\nnow parsing \"%s\"...\n", name);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	lineno = 1;
3817c478bd9Sstevel@tonic-gate 	line = file_buf;
3827c478bd9Sstevel@tonic-gate 	while (lend = find_line_end(line, &linc)) {
3837c478bd9Sstevel@tonic-gate 		/*
3847c478bd9Sstevel@tonic-gate 		 * Each line should start with valid data
3857c478bd9Sstevel@tonic-gate 		 * but leading white-space can be ignored
3867c478bd9Sstevel@tonic-gate 		 */
3877c478bd9Sstevel@tonic-gate 		while (line < lend) {
3887c478bd9Sstevel@tonic-gate 			if (*line != ' ' && *line != '\t')
3897c478bd9Sstevel@tonic-gate 				break;
3907c478bd9Sstevel@tonic-gate 			line++;
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 		/*
3947c478bd9Sstevel@tonic-gate 		 * Copy line into allocated space and null-terminate
3957c478bd9Sstevel@tonic-gate 		 * without the trailing line-feed.
3967c478bd9Sstevel@tonic-gate 		 */
3977c478bd9Sstevel@tonic-gate 		if ((llen = (lend - line)) != 0) {
3987c478bd9Sstevel@tonic-gate 			if ((cline = malloc(llen + 1)) == NULL)
3997c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "cannot alloc %u bytes "
4007c478bd9Sstevel@tonic-gate 				    "for line copy\n", llen);
4017c478bd9Sstevel@tonic-gate 			(void) memcpy(cline, line, llen);
4027c478bd9Sstevel@tonic-gate 			*(cline + llen) = '\0';
4037c478bd9Sstevel@tonic-gate 		} else
4047c478bd9Sstevel@tonic-gate 			cline = NULL;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		/*
4077c478bd9Sstevel@tonic-gate 		 * For blank and comment lines: possibly show a debug
4087c478bd9Sstevel@tonic-gate 		 * message and otherwise ignore them.  For other lines:
4097c478bd9Sstevel@tonic-gate 		 * parse into an arg vector and try to match the first
4107c478bd9Sstevel@tonic-gate 		 * arg with conftab keywords.  When a match is found,
4117c478bd9Sstevel@tonic-gate 		 * check for exact or minimum arg count, and call the
4127c478bd9Sstevel@tonic-gate 		 * action or handler routine; if handler does not return
4137c478bd9Sstevel@tonic-gate 		 * OKUP, set the referenced update value to NOUP so that
4147c478bd9Sstevel@tonic-gate 		 * later CPR or PM updates are skipped.
4157c478bd9Sstevel@tonic-gate 		 */
4167c478bd9Sstevel@tonic-gate 		if (llen == 0)
4177c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "\nline %d, blank...\n", lineno);
4187c478bd9Sstevel@tonic-gate 		else if (*line == '#')
4197c478bd9Sstevel@tonic-gate 			mesg(MDEBUG, "\nline %d, comment...\n", lineno);
4207c478bd9Sstevel@tonic-gate 		else if (cnt = build_args(cline, cline + llen)) {
4217c478bd9Sstevel@tonic-gate 			if ((cip = get_cinfo()) == NULL) {
4227c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "unrecognized keyword \"%s\"\n",
4237c478bd9Sstevel@tonic-gate 				    LINEARG(0));
4247c478bd9Sstevel@tonic-gate 			} else if (cnt != cip->argc &&
4257c478bd9Sstevel@tonic-gate 			    (cip->any == 0 || cnt < cip->argc)) {
4267c478bd9Sstevel@tonic-gate 				mesg(MEXIT, "found %d args, expect %d%s\n",
4277c478bd9Sstevel@tonic-gate 				    cnt, cip->argc, cip->any ? "+" : "");
4287c478bd9Sstevel@tonic-gate 			} else if (action)
4297c478bd9Sstevel@tonic-gate 				(*action)(line, llen + 1, cip);
4307c478bd9Sstevel@tonic-gate 			else if (cip->status->perm && (def_src || cip->alt)) {
4317c478bd9Sstevel@tonic-gate 				if ((*cip->handler)() != OKUP)
4327c478bd9Sstevel@tonic-gate 					cip->status->update = NOUP;
4337c478bd9Sstevel@tonic-gate 			} else {
4347c478bd9Sstevel@tonic-gate 				mesg(MDEBUG,
4357c478bd9Sstevel@tonic-gate 				    "==> handler skipped: %s_perm %d, "
4367c478bd9Sstevel@tonic-gate 				    "def_src %d, alt %d\n", cip->status->set,
4377c478bd9Sstevel@tonic-gate 				    cip->status->perm, def_src, cip->alt);
4387c478bd9Sstevel@tonic-gate 			}
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (cline)
4427c478bd9Sstevel@tonic-gate 			free(cline);
4437c478bd9Sstevel@tonic-gate 		line = lend + 1;
4447c478bd9Sstevel@tonic-gate 		lineno += linc;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 	lineno = 0;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	free(file_buf);
4497c478bd9Sstevel@tonic-gate }
450