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
5c42872d4Smh27603 * Common Development and Distribution License (the "License").
6c42872d4Smh27603 * 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 /*
220e751525SEric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include "pmconfig.h"
277c478bd9Sstevel@tonic-gate #include <deflt.h>
287c478bd9Sstevel@tonic-gate #include <pwd.h>
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #ifdef sparc
317c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
327c478bd9Sstevel@tonic-gate static char sf_cmt[] = "# Statefile\t\tPath\n";
337c478bd9Sstevel@tonic-gate #endif
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate static char as_cmt[] =
367c478bd9Sstevel@tonic-gate "# Auto-Shutdown\t\tIdle(min)\tStart/Finish(hh:mm)\tBehavior\n";
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate char **line_args;
397c478bd9Sstevel@tonic-gate int lineno = 0;
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * cpr and pm combined permission/update status
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate prmup_t cpr_status = { 0, OKUP, "cpr" };
457c478bd9Sstevel@tonic-gate prmup_t pm_status = { 0, OKUP, "pm" };
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate * For config file parsing to work correctly/efficiently, this table
507c478bd9Sstevel@tonic-gate * needs to be sorted by .keyword and any longer string like "device"
517c478bd9Sstevel@tonic-gate * must appear before a substring like "dev".
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate static cinfo_t conftab[] = {
542df1fe9cSrandyf "S3-support", S3sup, &pm_status, NULL, 2, 0, 1,
552df1fe9cSrandyf "autoS3", autoS3, &pm_status, NULL, 2, 0, 1,
567c478bd9Sstevel@tonic-gate "autopm", autopm, &pm_status, NULL, 2, 0, 1,
577c478bd9Sstevel@tonic-gate "autoshutdown", autosd, &cpr_status, as_cmt, 5, 0, 1,
58c42872d4Smh27603 "cpu-threshold", cputhr, &pm_status, NULL, 2, 0, 1,
590e751525SEric Saxe "cpu_deep_idle", cpuidle, &pm_status, NULL, 2, 0, 1,
600e751525SEric Saxe "cpupm", cpupm, &pm_status, NULL, 2, 1, 1,
617c478bd9Sstevel@tonic-gate "device-dependency-property",
627c478bd9Sstevel@tonic-gate ddprop, &pm_status, NULL, 3, 1, 1,
637c478bd9Sstevel@tonic-gate "device-dependency", devdep, &pm_status, NULL, 3, 1, 1,
647c478bd9Sstevel@tonic-gate "device-thresholds", devthr, &pm_status, NULL, 3, 1, 1,
657c478bd9Sstevel@tonic-gate "diskreads", dreads, &cpr_status, NULL, 2, 0, 1,
667c478bd9Sstevel@tonic-gate "idlecheck", idlechk, &cpr_status, NULL, 2, 0, 0,
677c478bd9Sstevel@tonic-gate "loadaverage", loadavg, &cpr_status, NULL, 2, 0, 1,
687c478bd9Sstevel@tonic-gate "nfsreqs", nfsreq, &cpr_status, NULL, 2, 0, 1,
697c478bd9Sstevel@tonic-gate #ifdef sparc
707c478bd9Sstevel@tonic-gate "statefile", sfpath, &cpr_status, sf_cmt, 2, 0, 0,
717c478bd9Sstevel@tonic-gate #endif
727c478bd9Sstevel@tonic-gate "system-threshold", systhr, &pm_status, NULL, 2, 0, 1,
737c478bd9Sstevel@tonic-gate "ttychars", tchars, &cpr_status, NULL, 2, 0, 1,
747c478bd9Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0, 0, 0,
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * Set cpr/pm permission from default file info.
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@tonic-gate static void
set_perm(char * defstr,char * user,int * perm,int cons)827c478bd9Sstevel@tonic-gate set_perm(char *defstr, char *user, int *perm, int cons)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate char *dinfo, *tk;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate * /etc/default/power entries are:
887c478bd9Sstevel@tonic-gate * all (all users + root)
897c478bd9Sstevel@tonic-gate * - (none + root)
907c478bd9Sstevel@tonic-gate * <user1[, user2...> (list users + root)
917c478bd9Sstevel@tonic-gate * console-owner (console onwer + root)
927c478bd9Sstevel@tonic-gate * Any error in reading/parsing the file limits the
937c478bd9Sstevel@tonic-gate * access requirement to root.
947c478bd9Sstevel@tonic-gate */
957c478bd9Sstevel@tonic-gate dinfo = defread(defstr);
967c478bd9Sstevel@tonic-gate mesg(MDEBUG, "set_perm: \"%s\", value \"%s\"\n",
977c478bd9Sstevel@tonic-gate defstr, dinfo ? dinfo : "NULL");
987c478bd9Sstevel@tonic-gate if (dinfo == NULL)
997c478bd9Sstevel@tonic-gate return;
1007c478bd9Sstevel@tonic-gate else if (strcmp(dinfo, "all") == 0)
1017c478bd9Sstevel@tonic-gate *perm = 1;
1027c478bd9Sstevel@tonic-gate else if (strcmp(dinfo, "console-owner") == 0)
1037c478bd9Sstevel@tonic-gate *perm = cons;
1047c478bd9Sstevel@tonic-gate else if (user != NULL &&
1057c478bd9Sstevel@tonic-gate (*dinfo == '<') && (tk = strrchr(++dinfo, '>'))) {
1067c478bd9Sstevel@tonic-gate /* Scan dinfo for a matching user. */
107*5009f788SIgor Kozhukhov for (*tk = '\0'; (tk = strtok(dinfo, ", ")) != NULL;
108*5009f788SIgor Kozhukhov dinfo = NULL) {
1097c478bd9Sstevel@tonic-gate mesg(MDEBUG, "match_user: cmp (\"%s\", \"%s\")\n",
1107c478bd9Sstevel@tonic-gate tk, user);
1117c478bd9Sstevel@tonic-gate if (strcmp(tk, user) == 0) {
1127c478bd9Sstevel@tonic-gate *perm = 1;
1137c478bd9Sstevel@tonic-gate break;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate * Lookup cpr/pm user permissions in "/etc/default/power".
1227c478bd9Sstevel@tonic-gate */
1237c478bd9Sstevel@tonic-gate void
lookup_perms(void)1247c478bd9Sstevel@tonic-gate lookup_perms(void)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate struct passwd *pent;
1277c478bd9Sstevel@tonic-gate struct stat stbuf;
1287c478bd9Sstevel@tonic-gate int cons_perm;
1297c478bd9Sstevel@tonic-gate char *user;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate if ((ruid = getuid()) == 0) {
1327c478bd9Sstevel@tonic-gate cpr_status.perm = pm_status.perm = 1;
1337c478bd9Sstevel@tonic-gate return;
1347c478bd9Sstevel@tonic-gate } else if ((pent = getpwuid(ruid)) != NULL) {
1357c478bd9Sstevel@tonic-gate user = pent->pw_name;
1367c478bd9Sstevel@tonic-gate } else {
1377c478bd9Sstevel@tonic-gate user = NULL;
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate if (defopen("/etc/default/power") == -1)
1417c478bd9Sstevel@tonic-gate return;
1427c478bd9Sstevel@tonic-gate if (stat("/dev/console", &stbuf) == -1)
1437c478bd9Sstevel@tonic-gate cons_perm = 0;
1447c478bd9Sstevel@tonic-gate else
1457c478bd9Sstevel@tonic-gate cons_perm = (ruid == stbuf.st_uid);
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate set_perm("PMCHANGEPERM=", user, &pm_status.perm, cons_perm);
1487c478bd9Sstevel@tonic-gate set_perm("CPRCHANGEPERM=", user, &cpr_status.perm, cons_perm);
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate (void) defopen(NULL);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate #ifdef sparc
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate * Lookup energystar-v[23] property and set estar_vers.
1577c478bd9Sstevel@tonic-gate */
1587c478bd9Sstevel@tonic-gate void
lookup_estar_vers(void)1597c478bd9Sstevel@tonic-gate lookup_estar_vers(void)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate char es_prop[] = "energystar-v?", *fmt = "%s init/access error\n";
1627c478bd9Sstevel@tonic-gate di_prom_handle_t ph;
1637c478bd9Sstevel@tonic-gate di_node_t node;
1647c478bd9Sstevel@tonic-gate uchar_t *prop_data;
1657c478bd9Sstevel@tonic-gate int last;
1667c478bd9Sstevel@tonic-gate char ch;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate if ((node = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
1697c478bd9Sstevel@tonic-gate mesg(MERR, fmt, "di_init");
1707c478bd9Sstevel@tonic-gate return;
1717c478bd9Sstevel@tonic-gate } else if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
1727c478bd9Sstevel@tonic-gate mesg(MERR, fmt, "di_prom_init");
1737c478bd9Sstevel@tonic-gate di_fini(node);
1747c478bd9Sstevel@tonic-gate return;
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate last = strlen(es_prop) - 1;
1777c478bd9Sstevel@tonic-gate for (ch = ESTAR_V2; ch <= ESTAR_V3; ch++) {
1787c478bd9Sstevel@tonic-gate es_prop[last] = ch;
1797c478bd9Sstevel@tonic-gate if (di_prom_prop_lookup_bytes(ph, node,
1807c478bd9Sstevel@tonic-gate es_prop, &prop_data) == 0) {
1817c478bd9Sstevel@tonic-gate mesg(MDEBUG, "get_estar_vers: %s prop found\n",
1827c478bd9Sstevel@tonic-gate es_prop);
1837c478bd9Sstevel@tonic-gate estar_vers = ch;
1847c478bd9Sstevel@tonic-gate break;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate di_prom_fini(ph);
1887c478bd9Sstevel@tonic-gate di_fini(node);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate #endif /* sparc */
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate * limit open() to the real user
1957c478bd9Sstevel@tonic-gate */
1967c478bd9Sstevel@tonic-gate static int
pmc_open(char * name,int oflag)1977c478bd9Sstevel@tonic-gate pmc_open(char *name, int oflag)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate uid_t euid;
2007c478bd9Sstevel@tonic-gate int fd;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate euid = geteuid();
2037c478bd9Sstevel@tonic-gate if (seteuid(ruid) == -1)
2047c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot reset euid to %d, %s\n",
2057c478bd9Sstevel@tonic-gate ruid, strerror(errno));
2067c478bd9Sstevel@tonic-gate fd = open(name, oflag);
2077c478bd9Sstevel@tonic-gate (void) seteuid(euid);
2087c478bd9Sstevel@tonic-gate return (fd);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate * Alloc space and read a config file; caller needs to free the space.
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate static char *
get_conf_data(char * name)2167c478bd9Sstevel@tonic-gate get_conf_data(char *name)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate struct stat stbuf;
2197c478bd9Sstevel@tonic-gate ssize_t nread;
2207c478bd9Sstevel@tonic-gate size_t size;
2217c478bd9Sstevel@tonic-gate char *buf;
2227c478bd9Sstevel@tonic-gate int fd;
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate if ((fd = pmc_open(name, O_RDONLY)) == -1)
2257c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot open %s\n", name);
2267c478bd9Sstevel@tonic-gate else if (fstat(fd, &stbuf) == -1)
2277c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot stat %s\n", name);
2287c478bd9Sstevel@tonic-gate size = (size_t)stbuf.st_size;
2297c478bd9Sstevel@tonic-gate def_src = (stbuf.st_ino == def_info.st_ino &&
2307c478bd9Sstevel@tonic-gate stbuf.st_dev == def_info.st_dev);
2317c478bd9Sstevel@tonic-gate if ((buf = malloc(size + 1)) == NULL)
2327c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot allocate %u for \"%s\"\n", size + 1, name);
2337c478bd9Sstevel@tonic-gate nread = read(fd, buf, size);
2347c478bd9Sstevel@tonic-gate (void) close(fd);
2357c478bd9Sstevel@tonic-gate if (nread != (ssize_t)size)
2367c478bd9Sstevel@tonic-gate mesg(MEXIT, "read error, expect %u, got %d, file \"%s\"\n",
2377c478bd9Sstevel@tonic-gate size, nread, name);
2387c478bd9Sstevel@tonic-gate *(buf + size) = '\0';
2397c478bd9Sstevel@tonic-gate return (buf);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate * Add an arg to line_args, adding space if needed.
2457c478bd9Sstevel@tonic-gate */
2467c478bd9Sstevel@tonic-gate static void
newarg(char * arg,int index)2477c478bd9Sstevel@tonic-gate newarg(char *arg, int index)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate static int alcnt;
2507c478bd9Sstevel@tonic-gate size_t size;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate if ((index + 1) > alcnt) {
2537c478bd9Sstevel@tonic-gate alcnt += 4;
2547c478bd9Sstevel@tonic-gate size = alcnt * sizeof (*line_args);
2557c478bd9Sstevel@tonic-gate if ((line_args = realloc(line_args, size)) == NULL)
2567c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot alloc %u for line args\n", size);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate *(line_args + index) = arg;
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate * Convert blank-delimited words into an arg vector and return
2647c478bd9Sstevel@tonic-gate * the arg count; character strings get null-terminated in place.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate static int
build_args(char * cline,char * tail)2677c478bd9Sstevel@tonic-gate build_args(char *cline, char *tail)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate extern int debug;
2707c478bd9Sstevel@tonic-gate char **vec, *arg, *cp;
2717c478bd9Sstevel@tonic-gate int cnt = 0;
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate * Search logic: look for "\\\n" as a continuation marker,
2757c478bd9Sstevel@tonic-gate * treat any other "\\*" as ordinary arg data, scan until a
2767c478bd9Sstevel@tonic-gate * white-space delimiter is found, and if the arg has length,
2777c478bd9Sstevel@tonic-gate * null-terminate and save arg to line_args. The scan includes
2787c478bd9Sstevel@tonic-gate * tail so the last arg is found without any special-case code.
2797c478bd9Sstevel@tonic-gate */
2807c478bd9Sstevel@tonic-gate for (arg = cp = cline; cp <= tail; cp++) {
2817c478bd9Sstevel@tonic-gate if (*cp == '\\') {
2827c478bd9Sstevel@tonic-gate if (*(cp + 1) && *(cp + 1) != '\n') {
2837c478bd9Sstevel@tonic-gate cp++;
2847c478bd9Sstevel@tonic-gate continue;
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate } else if (strchr(" \t\n", *cp) == NULL)
2877c478bd9Sstevel@tonic-gate continue;
2887c478bd9Sstevel@tonic-gate if (cp - arg) {
2897c478bd9Sstevel@tonic-gate *cp = '\0';
2907c478bd9Sstevel@tonic-gate newarg(arg, cnt++);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate arg = cp + 1;
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate newarg(NULL, cnt);
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate if (debug) {
2977c478bd9Sstevel@tonic-gate mesg(MDEBUG, "\nline %d, found %d args:\n", lineno, cnt);
2987c478bd9Sstevel@tonic-gate for (vec = line_args; *vec; vec++)
2997c478bd9Sstevel@tonic-gate mesg(MDEBUG, " \"%s\"\n", *vec);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate return (cnt);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate * Match leading keyword from a conf line and
3087c478bd9Sstevel@tonic-gate * return a reference to a config info struct.
3097c478bd9Sstevel@tonic-gate */
3107c478bd9Sstevel@tonic-gate static cinfo_t *
get_cinfo(void)3117c478bd9Sstevel@tonic-gate get_cinfo(void)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate cinfo_t *cip, *info = NULL;
3147c478bd9Sstevel@tonic-gate char *keyword;
3157c478bd9Sstevel@tonic-gate int chr_diff;
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * Scan the config table for a matching keyword; since the table
3197c478bd9Sstevel@tonic-gate * is sorted by keyword strings, a few optimizations can be done:
3207c478bd9Sstevel@tonic-gate * first compare only the first byte of the keyword, skip any
3217c478bd9Sstevel@tonic-gate * table string that starts with a lower ASCII value, compare the
3227c478bd9Sstevel@tonic-gate * full string only when the first byte matches, and stop checking
3237c478bd9Sstevel@tonic-gate * if the table string starts with a higher ASCII value.
3247c478bd9Sstevel@tonic-gate */
3257c478bd9Sstevel@tonic-gate keyword = LINEARG(0);
3267c478bd9Sstevel@tonic-gate for (cip = conftab; cip->keyword; cip++) {
3277c478bd9Sstevel@tonic-gate chr_diff = (int)(*cip->keyword - *keyword);
3287c478bd9Sstevel@tonic-gate #if 0
3297c478bd9Sstevel@tonic-gate mesg(MDEBUG, "line %d, ('%c' - '%c') = %d\n",
3307c478bd9Sstevel@tonic-gate lineno, *cip->keyword, *line, chr_diff);
3317c478bd9Sstevel@tonic-gate #endif
3327c478bd9Sstevel@tonic-gate if (chr_diff < 0)
3337c478bd9Sstevel@tonic-gate continue;
3347c478bd9Sstevel@tonic-gate else if (chr_diff == 0) {
3357c478bd9Sstevel@tonic-gate if (strcmp(keyword, cip->keyword) == 0) {
3367c478bd9Sstevel@tonic-gate info = cip;
3377c478bd9Sstevel@tonic-gate break;
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate } else
3407c478bd9Sstevel@tonic-gate break;
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate return (info);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate * Find the end of a [possibly continued] conf line
3487c478bd9Sstevel@tonic-gate * and record the real/lf-delimited line count at *lcnt.
3497c478bd9Sstevel@tonic-gate */
3507c478bd9Sstevel@tonic-gate static char *
find_line_end(char * line,int * lcnt)3517c478bd9Sstevel@tonic-gate find_line_end(char *line, int *lcnt)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate char *next, *lf;
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate *lcnt = 0;
3567c478bd9Sstevel@tonic-gate next = line;
357*5009f788SIgor Kozhukhov while ((lf = strchr(next, '\n')) != NULL) {
3587c478bd9Sstevel@tonic-gate (*lcnt)++;
3597c478bd9Sstevel@tonic-gate if (lf == line || (*(lf - 1) != '\\') || *(lf + 1) == '\0')
3607c478bd9Sstevel@tonic-gate break;
3617c478bd9Sstevel@tonic-gate next = lf + 1;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate return (lf);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate * Parse the named conf file and for each conf line
3697c478bd9Sstevel@tonic-gate * call the action routine or conftab handler routine.
3707c478bd9Sstevel@tonic-gate */
3717c478bd9Sstevel@tonic-gate void
parse_conf_file(char * name,vact_t action,boolean_t first_parse)372731682d8SSeth Goldberg parse_conf_file(char *name, vact_t action, boolean_t first_parse)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate char *file_buf, *cline, *line, *lend;
3757c478bd9Sstevel@tonic-gate cinfo_t *cip;
3767c478bd9Sstevel@tonic-gate int linc, cnt;
3777c478bd9Sstevel@tonic-gate size_t llen;
3782df1fe9cSrandyf int dontcare;
3792df1fe9cSrandyf
3802df1fe9cSrandyf /*
381731682d8SSeth Goldberg * Do the "implied default" for autoS3, but only before we
382731682d8SSeth Goldberg * start parsing the first conf file.
3832df1fe9cSrandyf */
384731682d8SSeth Goldberg if (first_parse) {
3852df1fe9cSrandyf (void) S3_helper("S3-support-enable", "S3-support-disable",
3862df1fe9cSrandyf PM_ENABLE_S3, PM_DISABLE_S3, "S3-support", "default",
3872df1fe9cSrandyf &dontcare, -1);
388731682d8SSeth Goldberg }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate file_buf = get_conf_data(name);
3917c478bd9Sstevel@tonic-gate mesg(MDEBUG, "\nnow parsing \"%s\"...\n", name);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate lineno = 1;
3947c478bd9Sstevel@tonic-gate line = file_buf;
395*5009f788SIgor Kozhukhov while ((lend = find_line_end(line, &linc)) != NULL) {
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * Each line should start with valid data
3987c478bd9Sstevel@tonic-gate * but leading white-space can be ignored
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate while (line < lend) {
4017c478bd9Sstevel@tonic-gate if (*line != ' ' && *line != '\t')
4027c478bd9Sstevel@tonic-gate break;
4037c478bd9Sstevel@tonic-gate line++;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate * Copy line into allocated space and null-terminate
4087c478bd9Sstevel@tonic-gate * without the trailing line-feed.
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate if ((llen = (lend - line)) != 0) {
4117c478bd9Sstevel@tonic-gate if ((cline = malloc(llen + 1)) == NULL)
4127c478bd9Sstevel@tonic-gate mesg(MEXIT, "cannot alloc %u bytes "
4137c478bd9Sstevel@tonic-gate "for line copy\n", llen);
4147c478bd9Sstevel@tonic-gate (void) memcpy(cline, line, llen);
4157c478bd9Sstevel@tonic-gate *(cline + llen) = '\0';
4167c478bd9Sstevel@tonic-gate } else
4177c478bd9Sstevel@tonic-gate cline = NULL;
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * For blank and comment lines: possibly show a debug
4217c478bd9Sstevel@tonic-gate * message and otherwise ignore them. For other lines:
4227c478bd9Sstevel@tonic-gate * parse into an arg vector and try to match the first
4237c478bd9Sstevel@tonic-gate * arg with conftab keywords. When a match is found,
4247c478bd9Sstevel@tonic-gate * check for exact or minimum arg count, and call the
4257c478bd9Sstevel@tonic-gate * action or handler routine; if handler does not return
4267c478bd9Sstevel@tonic-gate * OKUP, set the referenced update value to NOUP so that
4277c478bd9Sstevel@tonic-gate * later CPR or PM updates are skipped.
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate if (llen == 0)
4307c478bd9Sstevel@tonic-gate mesg(MDEBUG, "\nline %d, blank...\n", lineno);
4317c478bd9Sstevel@tonic-gate else if (*line == '#')
4327c478bd9Sstevel@tonic-gate mesg(MDEBUG, "\nline %d, comment...\n", lineno);
433*5009f788SIgor Kozhukhov else if ((cnt = build_args(cline, cline + llen)) != 0) {
4347c478bd9Sstevel@tonic-gate if ((cip = get_cinfo()) == NULL) {
4357c478bd9Sstevel@tonic-gate mesg(MEXIT, "unrecognized keyword \"%s\"\n",
4367c478bd9Sstevel@tonic-gate LINEARG(0));
4377c478bd9Sstevel@tonic-gate } else if (cnt != cip->argc &&
4387c478bd9Sstevel@tonic-gate (cip->any == 0 || cnt < cip->argc)) {
4397c478bd9Sstevel@tonic-gate mesg(MEXIT, "found %d args, expect %d%s\n",
4407c478bd9Sstevel@tonic-gate cnt, cip->argc, cip->any ? "+" : "");
4417c478bd9Sstevel@tonic-gate } else if (action)
4427c478bd9Sstevel@tonic-gate (*action)(line, llen + 1, cip);
4437c478bd9Sstevel@tonic-gate else if (cip->status->perm && (def_src || cip->alt)) {
4447c478bd9Sstevel@tonic-gate if ((*cip->handler)() != OKUP)
4457c478bd9Sstevel@tonic-gate cip->status->update = NOUP;
4467c478bd9Sstevel@tonic-gate } else {
4477c478bd9Sstevel@tonic-gate mesg(MDEBUG,
4487c478bd9Sstevel@tonic-gate "==> handler skipped: %s_perm %d, "
4497c478bd9Sstevel@tonic-gate "def_src %d, alt %d\n", cip->status->set,
4507c478bd9Sstevel@tonic-gate cip->status->perm, def_src, cip->alt);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate if (cline)
4557c478bd9Sstevel@tonic-gate free(cline);
4567c478bd9Sstevel@tonic-gate line = lend + 1;
4577c478bd9Sstevel@tonic-gate lineno += linc;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate lineno = 0;
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate free(file_buf);
4622df1fe9cSrandyf
4632df1fe9cSrandyf if (verify) {
4642df1fe9cSrandyf int ret = ioctl(pm_fd, PM_GET_PM_STATE, NULL);
4652df1fe9cSrandyf if (ret < 0) {
4662df1fe9cSrandyf mesg(MDEBUG, "Cannot get PM state: %s\n",
4672df1fe9cSrandyf strerror(errno));
4682df1fe9cSrandyf }
4692df1fe9cSrandyf switch (ret) {
4702df1fe9cSrandyf case PM_SYSTEM_PM_ENABLED:
4712df1fe9cSrandyf mesg(MDEBUG, "Autopm Enabled\n");
4722df1fe9cSrandyf break;
4732df1fe9cSrandyf case PM_SYSTEM_PM_DISABLED:
4742df1fe9cSrandyf mesg(MDEBUG, "Autopm Disabled\n");
4752df1fe9cSrandyf break;
4762df1fe9cSrandyf }
4772df1fe9cSrandyf ret = ioctl(pm_fd, PM_GET_S3_SUPPORT_STATE, NULL);
4782df1fe9cSrandyf if (ret < 0) {
4792df1fe9cSrandyf mesg(MDEBUG, "Cannot get PM state: %s\n",
4802df1fe9cSrandyf strerror(errno));
4812df1fe9cSrandyf }
4822df1fe9cSrandyf switch (ret) {
4832df1fe9cSrandyf case PM_S3_SUPPORT_ENABLED:
4842df1fe9cSrandyf mesg(MDEBUG, "S3 support Enabled\n");
4852df1fe9cSrandyf break;
4862df1fe9cSrandyf case PM_S3_SUPPORT_DISABLED:
4872df1fe9cSrandyf mesg(MDEBUG, "S3 support Disabled\n");
4882df1fe9cSrandyf break;
4892df1fe9cSrandyf }
4902df1fe9cSrandyf ret = ioctl(pm_fd, PM_GET_AUTOS3_STATE, NULL);
4912df1fe9cSrandyf if (ret < 0) {
4922df1fe9cSrandyf mesg(MDEBUG, "Cannot get PM state: %s\n",
4932df1fe9cSrandyf strerror(errno));
4942df1fe9cSrandyf }
4952df1fe9cSrandyf switch (ret) {
4962df1fe9cSrandyf case PM_AUTOS3_ENABLED:
4972df1fe9cSrandyf mesg(MDEBUG, "AutoS3 Enabled\n");
4982df1fe9cSrandyf break;
4992df1fe9cSrandyf case PM_AUTOS3_DISABLED:
5002df1fe9cSrandyf mesg(MDEBUG, "AutoS3 Disabled\n");
5012df1fe9cSrandyf break;
5022df1fe9cSrandyf }
5032df1fe9cSrandyf }
5047c478bd9Sstevel@tonic-gate }
505