xref: /illumos-gate/usr/src/cmd/power/conf.c (revision 2a8bcb4e)
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
52df1fe9cSrandyf  * Common Development and Distribution License (the "License").
62df1fe9cSrandyf  * 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 /*
22b03982bdSBick Torrejon  * 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 /*
277c478bd9Sstevel@tonic-gate  * "pmconfig" performs a mixture of Energy-Star configuration tasks
287c478bd9Sstevel@tonic-gate  * for both CheckPoint-Resume and Power-Management services.
297c478bd9Sstevel@tonic-gate  * Tasks include parsing a config file (usually "/etc/power.conf"),
307c478bd9Sstevel@tonic-gate  * updating CPR and PM config files, and setting various PM options
317c478bd9Sstevel@tonic-gate  * via ioctl requests.  From the mix, pmconfig should have a more
327c478bd9Sstevel@tonic-gate  * generalized name similar to "estarconfig".
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * OPTIONS:
357c478bd9Sstevel@tonic-gate  * "-r"		reset CPR and PM options to default and exit.
367c478bd9Sstevel@tonic-gate  * "-f file"	specify an alternate config file; this is a
377c478bd9Sstevel@tonic-gate  *		private/non-advertised option used by "dtpower".
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "pmconfig.h"
417c478bd9Sstevel@tonic-gate #include <sys/wait.h>
427c478bd9Sstevel@tonic-gate #include <signal.h>
437c478bd9Sstevel@tonic-gate #include <stdarg.h>
447c478bd9Sstevel@tonic-gate #include <locale.h>
457c478bd9Sstevel@tonic-gate #include "powerd.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	MCCPY_FIELD(dst, src, field) \
497c478bd9Sstevel@tonic-gate 	(void) memccpy(&dst.field, &src.field, 0, sizeof (dst.field) - 1)
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static char conf_header[] =
537c478bd9Sstevel@tonic-gate "#\n"
547c478bd9Sstevel@tonic-gate "# Copyright 1996-2002 Sun Microsystems, Inc.  All rights reserved.\n"
557c478bd9Sstevel@tonic-gate "# Use is subject to license terms.\n"
567c478bd9Sstevel@tonic-gate "#\n"
577c478bd9Sstevel@tonic-gate "# Power Management Configuration File\n"
587c478bd9Sstevel@tonic-gate "#\n\n";
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static char *prog;
617c478bd9Sstevel@tonic-gate static char *cpr_conf = CPR_CONFIG;
627c478bd9Sstevel@tonic-gate static char tmp_conf[] = "/etc/.tmp.conf.XXXXXX";
637c478bd9Sstevel@tonic-gate static char orig_conf[] = "/etc/power.conf-Orig";
647c478bd9Sstevel@tonic-gate static char default_conf[] = "/etc/power.conf";
657c478bd9Sstevel@tonic-gate static char *power_conf = default_conf;
667c478bd9Sstevel@tonic-gate static pid_t powerd_pid;
677c478bd9Sstevel@tonic-gate static prmup_t *checkup;
687c478bd9Sstevel@tonic-gate static int tmp_fd;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate char estar_vers = ESTAR_VNONE;
717c478bd9Sstevel@tonic-gate int ua_err = 0;
727c478bd9Sstevel@tonic-gate int debug = 0;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static struct cprconfig disk_cc;
757c478bd9Sstevel@tonic-gate struct cprconfig new_cc;
767c478bd9Sstevel@tonic-gate struct stat def_info;
777c478bd9Sstevel@tonic-gate static int fflag, rflag;
787c478bd9Sstevel@tonic-gate int pm_fd;
797c478bd9Sstevel@tonic-gate uid_t ruid;
807c478bd9Sstevel@tonic-gate int def_src;
812df1fe9cSrandyf /*
822df1fe9cSrandyf  * Until we get more graphics driver support, we only enable autopm,
832df1fe9cSrandyf  * S3 support and autoS3 by default on X86 systems that are on our whitelist.
842df1fe9cSrandyf  */
852df1fe9cSrandyf int whitelist_only = 1;
862df1fe9cSrandyf 
872df1fe9cSrandyf int verify = 0;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate static void
cleanup(void)917c478bd9Sstevel@tonic-gate cleanup(void)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	free(line_args);
947c478bd9Sstevel@tonic-gate 	if (access(tmp_conf, F_OK) == 0)
957c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_conf);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Multi-purpose message output routine; also exits when
1017c478bd9Sstevel@tonic-gate  * (status == MEXIT), other status is non-fatal.
1027c478bd9Sstevel@tonic-gate  * VARARGS2
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate void
mesg(int code,char * fmt,...)1057c478bd9Sstevel@tonic-gate mesg(int code, char *fmt, ...)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	va_list vargs;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	/*
1107c478bd9Sstevel@tonic-gate 	 * debug is checked once here, avoiding N duplicate checks
1117c478bd9Sstevel@tonic-gate 	 * before each MDEBUG caller and unnecessary text dupduplication.
1127c478bd9Sstevel@tonic-gate 	 */
1137c478bd9Sstevel@tonic-gate 	if (debug == 0) {
1147c478bd9Sstevel@tonic-gate 		/*
1157c478bd9Sstevel@tonic-gate 		 * If debug is not enabled, skip a debug message;
1167c478bd9Sstevel@tonic-gate 		 * lead with the program name for an error message,
1177c478bd9Sstevel@tonic-gate 		 * and follow with a filename and line number if an
1187c478bd9Sstevel@tonic-gate 		 * error occurs while parsing a conf file.
1197c478bd9Sstevel@tonic-gate 		 */
1207c478bd9Sstevel@tonic-gate 		if (code == MDEBUG)
1217c478bd9Sstevel@tonic-gate 			return;
122*80148899SSurya Prakki 		(void) fprintf(stderr, "%s: ", prog);
1237c478bd9Sstevel@tonic-gate 		if (lineno)
124*80148899SSurya Prakki 			(void) fprintf(stderr,
125*80148899SSurya Prakki 			    "\"%s\" line %d, ", power_conf, lineno);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	va_start(vargs, fmt);
1297c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, gettext(fmt), vargs);
1307c478bd9Sstevel@tonic-gate 	va_end(vargs);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	if (code == MEXIT) {
1337c478bd9Sstevel@tonic-gate 		cleanup();
1347c478bd9Sstevel@tonic-gate 		exit(MEXIT);
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static void
usage(void)1407c478bd9Sstevel@tonic-gate usage(void)
1417c478bd9Sstevel@tonic-gate {
1421dc065c6Smh 	(void) fprintf(stderr, gettext("Usage: %s [-r]\n"), prog);
1437c478bd9Sstevel@tonic-gate 	exit(1);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Lookup estar version, check if uadmin() service is supported,
1497c478bd9Sstevel@tonic-gate  * and read cpr_config info from disk.
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate static void
get_cpr_info(void)1527c478bd9Sstevel@tonic-gate get_cpr_info(void)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	ssize_t nread;
1557c478bd9Sstevel@tonic-gate 	char *err_fmt;
1567c478bd9Sstevel@tonic-gate 	int fd;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate #ifdef sparc
1597c478bd9Sstevel@tonic-gate 	lookup_estar_vers();
1607c478bd9Sstevel@tonic-gate 	if (estar_vers == ESTAR_V2)
1617c478bd9Sstevel@tonic-gate 		new_cc.is_cpr_default = 1;
1627c478bd9Sstevel@tonic-gate 	else if (estar_vers == ESTAR_V3)
1637c478bd9Sstevel@tonic-gate 		new_cc.is_autopm_default = 1;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (uadmin(A_FREEZE, AD_CHECK, 0) == 0)
1667c478bd9Sstevel@tonic-gate 		new_cc.is_cpr_capable = 1;
1677c478bd9Sstevel@tonic-gate 	else
1687c478bd9Sstevel@tonic-gate 		ua_err = errno;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/tod", O_RDONLY)) != -1) {
1717c478bd9Sstevel@tonic-gate 		new_cc.is_autowakeup_capable = 1;
1727c478bd9Sstevel@tonic-gate 		(void) close(fd);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate #endif /* sparc */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 * Read in the cpr conf file.  If any open or read error occurs,
1787c478bd9Sstevel@tonic-gate 	 * display an error message only for a non-root user.  The file
1797c478bd9Sstevel@tonic-gate 	 * may not exist on a newly installed system.
1807c478bd9Sstevel@tonic-gate 	 */
1817c478bd9Sstevel@tonic-gate 	err_fmt = "%s %s; please rerun %s as root\n";
1827c478bd9Sstevel@tonic-gate 	if ((fd = open(cpr_conf, O_RDONLY)) == -1) {
1837c478bd9Sstevel@tonic-gate 		if (ruid)
1847c478bd9Sstevel@tonic-gate 			mesg(MEXIT, err_fmt, gettext("cannot open"),
1857c478bd9Sstevel@tonic-gate 			    cpr_conf, prog);
1867c478bd9Sstevel@tonic-gate 	} else {
1877c478bd9Sstevel@tonic-gate 		nread = read(fd, &disk_cc, sizeof (disk_cc));
1887c478bd9Sstevel@tonic-gate 		(void) close(fd);
1897c478bd9Sstevel@tonic-gate 		if (nread != (ssize_t)sizeof (disk_cc)) {
1907c478bd9Sstevel@tonic-gate 			if (ruid)
1917c478bd9Sstevel@tonic-gate 				mesg(MEXIT, err_fmt, cpr_conf,
1927c478bd9Sstevel@tonic-gate 				    gettext("file corrupted"), prog);
1937c478bd9Sstevel@tonic-gate 			else {
1947c478bd9Sstevel@tonic-gate 				(void) unlink(cpr_conf);
1957c478bd9Sstevel@tonic-gate 				bzero(&disk_cc, sizeof (disk_cc));
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * Unconfigure and reset PM, device is left open for later use.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate static void
pm_rem_reset(void)2067c478bd9Sstevel@tonic-gate pm_rem_reset(void)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	char *err_fmt = NULL;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if ((pm_fd = open("/dev/pm", O_RDWR)) == -1)
2117c478bd9Sstevel@tonic-gate 		err_fmt = "cannot open \"/dev/pm\": %s\n";
2127c478bd9Sstevel@tonic-gate 	else if (ioctl(pm_fd, PM_RESET_PM, 0) == -1)
2137c478bd9Sstevel@tonic-gate 		err_fmt = "cannot reset pm state: %s\n";
2147c478bd9Sstevel@tonic-gate 	if (err_fmt)
2157c478bd9Sstevel@tonic-gate 		mesg(MEXIT, err_fmt, strerror(errno));
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static void
get_powerd_pid(void)2207c478bd9Sstevel@tonic-gate get_powerd_pid(void)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	char pidstr[16];
2237c478bd9Sstevel@tonic-gate 	int fd;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if ((fd = open(PIDPATH, O_RDONLY)) == -1)
2267c478bd9Sstevel@tonic-gate 		return;
2277c478bd9Sstevel@tonic-gate 	bzero(pidstr, sizeof (pidstr));
2287c478bd9Sstevel@tonic-gate 	if (read(fd, pidstr, sizeof (pidstr)) > 0) {
2297c478bd9Sstevel@tonic-gate 		powerd_pid = atoi(pidstr);
2307c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "got powerd pid %ld\n", powerd_pid);
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 	(void) close(fd);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate  * Write revised cprconfig struct to disk based on perms;
2387c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate static int
update_cprconfig(void)2417c478bd9Sstevel@tonic-gate update_cprconfig(void)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	struct cprconfig *wrt_cc = &new_cc;
2447c478bd9Sstevel@tonic-gate 	char *err_fmt = NULL;
2457c478bd9Sstevel@tonic-gate 	int fd;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	if (rflag) {
2487c478bd9Sstevel@tonic-gate 		/* For "pmconfig -r" case, copy select cpr-related fields. */
2497c478bd9Sstevel@tonic-gate 		new_cc.cf_magic = disk_cc.cf_magic;
2507c478bd9Sstevel@tonic-gate 		new_cc.cf_type = disk_cc.cf_type;
2517c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_path);
2527c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_fs);
2537c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_devfs);
2547c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_dev_prom);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	if (!pm_status.perm) {
2587c478bd9Sstevel@tonic-gate 		if (cpr_status.update == NOUP)
2597c478bd9Sstevel@tonic-gate 			return (1);
2607c478bd9Sstevel@tonic-gate 		/* save new struct data with old autopm setting */
2617c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, apm_behavior);
2627c478bd9Sstevel@tonic-gate 	} else if (!cpr_status.perm) {
2637c478bd9Sstevel@tonic-gate 		if (pm_status.update == NOUP)
2647c478bd9Sstevel@tonic-gate 			return (1);
2657c478bd9Sstevel@tonic-gate 		/* save original struct with new autopm setting */
2667c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(disk_cc, new_cc, apm_behavior);
2677c478bd9Sstevel@tonic-gate 		wrt_cc = &disk_cc;
2687c478bd9Sstevel@tonic-gate 	} else if (cpr_status.update == NOUP || pm_status.update == NOUP)
2697c478bd9Sstevel@tonic-gate 		return (1);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if ((fd = open(cpr_conf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1)
2727c478bd9Sstevel@tonic-gate 		err_fmt = "cannot open/create \"%s\", %s\n";
2737c478bd9Sstevel@tonic-gate 	else if (write(fd, wrt_cc, sizeof (*wrt_cc)) != sizeof (*wrt_cc))
2747c478bd9Sstevel@tonic-gate 		err_fmt = "error writing \"%s\", %s\n";
2757c478bd9Sstevel@tonic-gate 	if (err_fmt)
2767c478bd9Sstevel@tonic-gate 		mesg(MERR, err_fmt, cpr_conf, strerror(errno));
277fe3e2633SEric Taylor 	if (fd != -1)
278fe3e2633SEric Taylor 		(void) close(fd);
2797c478bd9Sstevel@tonic-gate 	return (err_fmt != NULL);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate  * Signal old powerd when there's a valid pid, or start a new one;
2857c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate static int
restart_powerd(void)2887c478bd9Sstevel@tonic-gate restart_powerd(void)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	char *powerd = "/usr/lib/power/powerd";
2917c478bd9Sstevel@tonic-gate 	int status = 0;
2927c478bd9Sstevel@tonic-gate 	pid_t pid, wp;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (powerd_pid > 0) {
2957c478bd9Sstevel@tonic-gate 		if (sigsend(P_PID, powerd_pid, SIGHUP) == 0)
2967c478bd9Sstevel@tonic-gate 			return (0);
2977c478bd9Sstevel@tonic-gate 		else if (errno != ESRCH) {
2987c478bd9Sstevel@tonic-gate 			mesg(MERR, "cannot deliver hangup to powerd\n");
2997c478bd9Sstevel@tonic-gate 			return (1);
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == NOPID)
3047c478bd9Sstevel@tonic-gate 		wp = -1;
3057c478bd9Sstevel@tonic-gate 	else if (pid == P_MYPID) {
3067c478bd9Sstevel@tonic-gate 		(void) setreuid(0, 0);
3077c478bd9Sstevel@tonic-gate 		(void) setregid(0, 0);
3087c478bd9Sstevel@tonic-gate 		(void) setgroups(0, NULL);
3092df1fe9cSrandyf 		if (debug)
3102df1fe9cSrandyf 			(void) execle(powerd, powerd, "-d", NULL, NULL);
3112df1fe9cSrandyf 		else
3122df1fe9cSrandyf 			(void) execle(powerd, powerd, NULL, NULL);
3137c478bd9Sstevel@tonic-gate 		exit(1);
3147c478bd9Sstevel@tonic-gate 	} else {
3157c478bd9Sstevel@tonic-gate 		do {
3167c478bd9Sstevel@tonic-gate 			wp = waitpid(pid, &status, 0);
3177c478bd9Sstevel@tonic-gate 		} while (wp == -1 && errno == EINTR);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if (wp == -1)
3217c478bd9Sstevel@tonic-gate 		mesg(MERR, "could not start %s\n", powerd);
3227c478bd9Sstevel@tonic-gate 	return (wp == -1 || status != 0);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate static void
save_orig(void)3277c478bd9Sstevel@tonic-gate save_orig(void)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	static char *args[] = { "/usr/bin/cp", default_conf, orig_conf, NULL };
3307c478bd9Sstevel@tonic-gate 	struct stat stbuf;
3317c478bd9Sstevel@tonic-gate 	int pid;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (stat(orig_conf, &stbuf) == 0 && stbuf.st_size)
3347c478bd9Sstevel@tonic-gate 		return;
3357c478bd9Sstevel@tonic-gate 	pid = fork();
3367c478bd9Sstevel@tonic-gate 	if (pid == NOPID)
3377c478bd9Sstevel@tonic-gate 		return;
3387c478bd9Sstevel@tonic-gate 	else if (pid == P_MYPID) {
3397c478bd9Sstevel@tonic-gate 		(void) execve(args[0], args, NULL);
3407c478bd9Sstevel@tonic-gate 		exit(1);
3417c478bd9Sstevel@tonic-gate 	} else
3427c478bd9Sstevel@tonic-gate 		(void) waitpid(pid, NULL, 0);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate static void
tmp_write(void * buf,size_t len)3477c478bd9Sstevel@tonic-gate tmp_write(void *buf, size_t len)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate 	if (write(tmp_fd, buf, len) != (ssize_t)len)
3507c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "error writing tmp file, %s\n", strerror(errno));
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static void
tmp_save_line(char * line,size_t len,cinfo_t * cip)3557c478bd9Sstevel@tonic-gate tmp_save_line(char *line, size_t len, cinfo_t *cip)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	if (cip && cip->cmt)
3587c478bd9Sstevel@tonic-gate 		tmp_write(cip->cmt, strlen(cip->cmt));
3597c478bd9Sstevel@tonic-gate 	tmp_write(line, len);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate  * Filter conf lines and write them to the tmp file.
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate static void
filter(char * line,size_t len,cinfo_t * cip)3677c478bd9Sstevel@tonic-gate filter(char *line, size_t len, cinfo_t *cip)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	int selected;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/*
3727c478bd9Sstevel@tonic-gate 	 * Lines from an alt conf file are selected when either:
3737c478bd9Sstevel@tonic-gate 	 * cip is NULL (keyword not matched, probably an old-style device),
3747c478bd9Sstevel@tonic-gate 	 * OR: it's both OK to accept the conf line (alt) AND either:
3757c478bd9Sstevel@tonic-gate 	 * preference is not set (NULL checkup) OR the cpr/pm preference
3767c478bd9Sstevel@tonic-gate 	 * (checkup) matches conftab status.
3777c478bd9Sstevel@tonic-gate 	 */
3787c478bd9Sstevel@tonic-gate 	selected = (cip == NULL || (cip->alt &&
3797c478bd9Sstevel@tonic-gate 	    (checkup == NULL || checkup == cip->status)));
3807c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "filter: set \"%s\", selected %d\n",
3817c478bd9Sstevel@tonic-gate 	    cip ? cip->status->set : "none", selected);
3827c478bd9Sstevel@tonic-gate 	if (selected)
3837c478bd9Sstevel@tonic-gate 		tmp_save_line(line, len, cip);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate  * Set checkup for conf line selection and parse a conf file with filtering.
3897c478bd9Sstevel@tonic-gate  * When pref is NULL, filter selects all conf lines from the new conf file;
3907c478bd9Sstevel@tonic-gate  * otherwise filter selects only cpr or pm related lines from the new or
3917c478bd9Sstevel@tonic-gate  * default conf file based on cpr or pm perm.
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static void
conf_scanner(prmup_t * pref)3947c478bd9Sstevel@tonic-gate conf_scanner(prmup_t *pref)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "\nscanning set is %s\n", pref ? pref->set : "both");
3977c478bd9Sstevel@tonic-gate 	checkup = pref;
3987c478bd9Sstevel@tonic-gate 	parse_conf_file((pref == NULL || pref->perm)
399731682d8SSeth Goldberg 	    ? power_conf : default_conf, filter, B_FALSE);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * Search for any non-alt entries, call the handler routine,
4057c478bd9Sstevel@tonic-gate  * and write entries to the tmp file.
4067c478bd9Sstevel@tonic-gate  */
4077c478bd9Sstevel@tonic-gate static void
search(char * line,size_t len,cinfo_t * cip)4087c478bd9Sstevel@tonic-gate search(char *line, size_t len, cinfo_t *cip)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	int skip;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	skip = (cip == NULL || cip->alt);
4137c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "search: %s\n", skip ? "skipped" : "retained");
4147c478bd9Sstevel@tonic-gate 	if (skip)
4157c478bd9Sstevel@tonic-gate 		return;
4167c478bd9Sstevel@tonic-gate 	if (cip->status->perm)
4177c478bd9Sstevel@tonic-gate 		(void) (*cip->handler)();
4187c478bd9Sstevel@tonic-gate 	tmp_save_line(line, len, cip);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * When perm and update status are OK, write a new conf file
4247c478bd9Sstevel@tonic-gate  * and rename to default_conf with the original attributes;
4257c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate static int
write_conf(void)4287c478bd9Sstevel@tonic-gate write_conf(void)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	char *name, *err_str = NULL;
4317c478bd9Sstevel@tonic-gate 	struct stat stbuf;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if ((cpr_status.perm && cpr_status.update != OKUP) ||
4347c478bd9Sstevel@tonic-gate 	    (pm_status.perm && pm_status.update != OKUP)) {
4357c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\nconf not written, "
4367c478bd9Sstevel@tonic-gate 		    "(cpr perm %d update %d), (pm perm %d update %d)\n",
4377c478bd9Sstevel@tonic-gate 		    cpr_status.perm, cpr_status.update,
4387c478bd9Sstevel@tonic-gate 		    pm_status.perm, pm_status.update);
4397c478bd9Sstevel@tonic-gate 		return (1);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	save_orig();
4437c478bd9Sstevel@tonic-gate 	if ((tmp_fd = mkstemp(tmp_conf)) == -1) {
4447c478bd9Sstevel@tonic-gate 		mesg(MERR, "cannot open/create tmp file \"%s\"\n", tmp_conf);
4457c478bd9Sstevel@tonic-gate 		return (1);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 	tmp_write(conf_header, sizeof (conf_header) - 1);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/*
4507c478bd9Sstevel@tonic-gate 	 * When both perms are set, save selected lines from the new file;
4517c478bd9Sstevel@tonic-gate 	 * otherwise save selected subsets from the new and default files.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (cpr_status.perm && pm_status.perm)
4547c478bd9Sstevel@tonic-gate 		conf_scanner(NULL);
4557c478bd9Sstevel@tonic-gate 	else {
4567c478bd9Sstevel@tonic-gate 		conf_scanner(&cpr_status);
4577c478bd9Sstevel@tonic-gate 		conf_scanner(&pm_status);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/*
4617c478bd9Sstevel@tonic-gate 	 * "dtpower" will craft an alt conf file with modified content from
4627c478bd9Sstevel@tonic-gate 	 * /etc/power.conf, but any alt conf file is not a trusted source;
4637c478bd9Sstevel@tonic-gate 	 * since some alt conf lines may be skipped, the trusted source is
4647c478bd9Sstevel@tonic-gate 	 * searched for those lines to retain their functionality.
4657c478bd9Sstevel@tonic-gate 	 */
466731682d8SSeth Goldberg 	parse_conf_file(default_conf, search, B_FALSE);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (stat(name = default_conf, &stbuf) == -1)
4717c478bd9Sstevel@tonic-gate 		err_str = "stat";
4727c478bd9Sstevel@tonic-gate 	else if (chmod(name = tmp_conf, stbuf.st_mode) == -1)
4737c478bd9Sstevel@tonic-gate 		err_str = "chmod";
4747c478bd9Sstevel@tonic-gate 	else if (chown(tmp_conf, stbuf.st_uid, stbuf.st_gid) == -1)
4757c478bd9Sstevel@tonic-gate 		err_str = "chown";
4767c478bd9Sstevel@tonic-gate 	else if (rename(tmp_conf, default_conf) == -1)
4777c478bd9Sstevel@tonic-gate 		err_str = "rename";
4787c478bd9Sstevel@tonic-gate 	else
4797c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\n\"%s\" renamed to \"%s\"\n",
4807c478bd9Sstevel@tonic-gate 		    tmp_conf, default_conf);
4817c478bd9Sstevel@tonic-gate 	if (err_str)
4827c478bd9Sstevel@tonic-gate 		mesg(MERR, "cannot %s \"%s\", %s\n",
4837c478bd9Sstevel@tonic-gate 		    err_str, name, strerror(errno));
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	return (err_str != NULL);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /* ARGSUSED */
4907c478bd9Sstevel@tonic-gate int
main(int cnt,char ** vec)4917c478bd9Sstevel@tonic-gate main(int cnt, char **vec)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate 	int rval = 0;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4967c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	for (prog = *vec++; *vec && **vec == '-'; vec++) {
4997c478bd9Sstevel@tonic-gate 		if (strlen(*vec) > 2)
5007c478bd9Sstevel@tonic-gate 			usage();
5017c478bd9Sstevel@tonic-gate 		switch (*(*vec + 1)) {
5027c478bd9Sstevel@tonic-gate 		case 'd':
5037c478bd9Sstevel@tonic-gate 			debug = 1;
5047c478bd9Sstevel@tonic-gate 			break;
5057c478bd9Sstevel@tonic-gate 		case 'f':
5067c478bd9Sstevel@tonic-gate 			fflag = 1;
5077c478bd9Sstevel@tonic-gate 			if ((power_conf = *++vec) == NULL)
5087c478bd9Sstevel@tonic-gate 				usage();
5097c478bd9Sstevel@tonic-gate 			break;
5107c478bd9Sstevel@tonic-gate 		case 'r':
5117c478bd9Sstevel@tonic-gate 			rflag = 1;
5127c478bd9Sstevel@tonic-gate 			break;
5132df1fe9cSrandyf 		case 'W':
5142df1fe9cSrandyf 			whitelist_only = 0;
5152df1fe9cSrandyf 			break;
5162df1fe9cSrandyf 		case 'v':
5172df1fe9cSrandyf 			verify = 1;
5182df1fe9cSrandyf 			break;
5197c478bd9Sstevel@tonic-gate 		default:
5207c478bd9Sstevel@tonic-gate 			usage();
5217c478bd9Sstevel@tonic-gate 			break;
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 	if (rflag && fflag)
5257c478bd9Sstevel@tonic-gate 		usage();
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	lookup_perms();
5287c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "ruid %d, perms: cpr %d, pm %d\n",
5297c478bd9Sstevel@tonic-gate 	    ruid, cpr_status.perm, pm_status.perm);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if ((!cpr_status.perm && !pm_status.perm) ||
5327c478bd9Sstevel@tonic-gate 	    (rflag && !(cpr_status.perm && pm_status.perm)))
5337c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "%s\n", strerror(EACCES));
5347c478bd9Sstevel@tonic-gate 	if (rflag == 0 && access(power_conf, R_OK))
5357c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "\"%s\" is not readable\n", power_conf);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	get_cpr_info();
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (pm_status.perm)
5407c478bd9Sstevel@tonic-gate 		pm_rem_reset();
5417c478bd9Sstevel@tonic-gate 	get_powerd_pid();
5427c478bd9Sstevel@tonic-gate 	(void) umask(022);
5437c478bd9Sstevel@tonic-gate 	if (rflag)
5447c478bd9Sstevel@tonic-gate 		return (update_cprconfig() || restart_powerd());
5457c478bd9Sstevel@tonic-gate 	if (stat(default_conf, &def_info) == -1)
5467c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot stat %s, %s\n", default_conf,
5477c478bd9Sstevel@tonic-gate 		    strerror(errno));
5487c478bd9Sstevel@tonic-gate 	new_cc.loadaverage_thold = DFLT_THOLD;
549731682d8SSeth Goldberg 	parse_conf_file(power_conf, NULL, B_TRUE);
5507c478bd9Sstevel@tonic-gate 	if (fflag)
5517c478bd9Sstevel@tonic-gate 		rval = write_conf();
5527c478bd9Sstevel@tonic-gate 	cleanup();
553b03982bdSBick Torrejon 	if (pm_status.perm)
554b03982bdSBick Torrejon 		(void) close(pm_fd);
5557c478bd9Sstevel@tonic-gate 	if (rval == 0)
5567c478bd9Sstevel@tonic-gate 		rval = (update_cprconfig() || restart_powerd());
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	return (rval);
5597c478bd9Sstevel@tonic-gate }
560