xref: /titanic_53/usr/src/cmd/power/conf.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 /*
30*7c478bd9Sstevel@tonic-gate  * "pmconfig" performs a mixture of Energy-Star configuration tasks
31*7c478bd9Sstevel@tonic-gate  * for both CheckPoint-Resume and Power-Management services.
32*7c478bd9Sstevel@tonic-gate  * Tasks include parsing a config file (usually "/etc/power.conf"),
33*7c478bd9Sstevel@tonic-gate  * updating CPR and PM config files, and setting various PM options
34*7c478bd9Sstevel@tonic-gate  * via ioctl requests.  From the mix, pmconfig should have a more
35*7c478bd9Sstevel@tonic-gate  * generalized name similar to "estarconfig".
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * OPTIONS:
38*7c478bd9Sstevel@tonic-gate  * "-r"		reset CPR and PM options to default and exit.
39*7c478bd9Sstevel@tonic-gate  * "-f file"	specify an alternate config file; this is a
40*7c478bd9Sstevel@tonic-gate  *		private/non-advertised option used by "dtpower".
41*7c478bd9Sstevel@tonic-gate  */
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include "pmconfig.h"
44*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
45*7c478bd9Sstevel@tonic-gate #include <signal.h>
46*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
47*7c478bd9Sstevel@tonic-gate #include <locale.h>
48*7c478bd9Sstevel@tonic-gate #include "powerd.h"
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #define	MCCPY_FIELD(dst, src, field) \
52*7c478bd9Sstevel@tonic-gate 	(void) memccpy(&dst.field, &src.field, 0, sizeof (dst.field) - 1)
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate static char conf_header[] =
56*7c478bd9Sstevel@tonic-gate "#\n"
57*7c478bd9Sstevel@tonic-gate "# Copyright 1996-2002 Sun Microsystems, Inc.  All rights reserved.\n"
58*7c478bd9Sstevel@tonic-gate "# Use is subject to license terms.\n"
59*7c478bd9Sstevel@tonic-gate "#\n"
60*7c478bd9Sstevel@tonic-gate "#pragma ident	\"@(#)power.conf	2.1	02/03/04 SMI\"\n"
61*7c478bd9Sstevel@tonic-gate "#\n"
62*7c478bd9Sstevel@tonic-gate "# Power Management Configuration File\n"
63*7c478bd9Sstevel@tonic-gate "#\n\n";
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static char *prog;
66*7c478bd9Sstevel@tonic-gate static char *cpr_conf = CPR_CONFIG;
67*7c478bd9Sstevel@tonic-gate static char tmp_conf[] = "/etc/.tmp.conf.XXXXXX";
68*7c478bd9Sstevel@tonic-gate static char orig_conf[] = "/etc/power.conf-Orig";
69*7c478bd9Sstevel@tonic-gate static char default_conf[] = "/etc/power.conf";
70*7c478bd9Sstevel@tonic-gate static char *power_conf = default_conf;
71*7c478bd9Sstevel@tonic-gate static pid_t powerd_pid;
72*7c478bd9Sstevel@tonic-gate static prmup_t *checkup;
73*7c478bd9Sstevel@tonic-gate static int tmp_fd;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate char estar_vers = ESTAR_VNONE;
76*7c478bd9Sstevel@tonic-gate int ua_err = 0;
77*7c478bd9Sstevel@tonic-gate int debug = 0;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static struct cprconfig disk_cc;
80*7c478bd9Sstevel@tonic-gate struct cprconfig new_cc;
81*7c478bd9Sstevel@tonic-gate struct stat def_info;
82*7c478bd9Sstevel@tonic-gate static int fflag, rflag;
83*7c478bd9Sstevel@tonic-gate int pm_fd;
84*7c478bd9Sstevel@tonic-gate uid_t ruid;
85*7c478bd9Sstevel@tonic-gate int def_src;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static void
89*7c478bd9Sstevel@tonic-gate cleanup(void)
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	free(line_args);
92*7c478bd9Sstevel@tonic-gate 	if (access(tmp_conf, F_OK) == 0)
93*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_conf);
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /*
98*7c478bd9Sstevel@tonic-gate  * Multi-purpose message output routine; also exits when
99*7c478bd9Sstevel@tonic-gate  * (status == MEXIT), other status is non-fatal.
100*7c478bd9Sstevel@tonic-gate  * VARARGS2
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate void
103*7c478bd9Sstevel@tonic-gate mesg(int code, char *fmt, ...)
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate 	va_list vargs;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	/*
108*7c478bd9Sstevel@tonic-gate 	 * debug is checked once here, avoiding N duplicate checks
109*7c478bd9Sstevel@tonic-gate 	 * before each MDEBUG caller and unnecessary text dupduplication.
110*7c478bd9Sstevel@tonic-gate 	 */
111*7c478bd9Sstevel@tonic-gate 	if (debug == 0) {
112*7c478bd9Sstevel@tonic-gate 		/*
113*7c478bd9Sstevel@tonic-gate 		 * If debug is not enabled, skip a debug message;
114*7c478bd9Sstevel@tonic-gate 		 * lead with the program name for an error message,
115*7c478bd9Sstevel@tonic-gate 		 * and follow with a filename and line number if an
116*7c478bd9Sstevel@tonic-gate 		 * error occurs while parsing a conf file.
117*7c478bd9Sstevel@tonic-gate 		 */
118*7c478bd9Sstevel@tonic-gate 		if (code == MDEBUG)
119*7c478bd9Sstevel@tonic-gate 			return;
120*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: ", prog);
121*7c478bd9Sstevel@tonic-gate 		if (lineno)
122*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "\"%s\" line %d, ", power_conf, lineno);
123*7c478bd9Sstevel@tonic-gate 	}
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	va_start(vargs, fmt);
126*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, gettext(fmt), vargs);
127*7c478bd9Sstevel@tonic-gate 	va_end(vargs);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	if (code == MEXIT) {
130*7c478bd9Sstevel@tonic-gate 		cleanup();
131*7c478bd9Sstevel@tonic-gate 		exit(MEXIT);
132*7c478bd9Sstevel@tonic-gate 	}
133*7c478bd9Sstevel@tonic-gate }
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate static void
137*7c478bd9Sstevel@tonic-gate usage(void)
138*7c478bd9Sstevel@tonic-gate {
139*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Usage: %s [-r]\n", prog);
140*7c478bd9Sstevel@tonic-gate 	exit(1);
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate /*
145*7c478bd9Sstevel@tonic-gate  * Lookup estar version, check if uadmin() service is supported,
146*7c478bd9Sstevel@tonic-gate  * and read cpr_config info from disk.
147*7c478bd9Sstevel@tonic-gate  */
148*7c478bd9Sstevel@tonic-gate static void
149*7c478bd9Sstevel@tonic-gate get_cpr_info(void)
150*7c478bd9Sstevel@tonic-gate {
151*7c478bd9Sstevel@tonic-gate 	ssize_t nread;
152*7c478bd9Sstevel@tonic-gate 	char *err_fmt;
153*7c478bd9Sstevel@tonic-gate 	int fd;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate #ifdef sparc
156*7c478bd9Sstevel@tonic-gate 	lookup_estar_vers();
157*7c478bd9Sstevel@tonic-gate 	if (estar_vers == ESTAR_V2)
158*7c478bd9Sstevel@tonic-gate 		new_cc.is_cpr_default = 1;
159*7c478bd9Sstevel@tonic-gate 	else if (estar_vers == ESTAR_V3)
160*7c478bd9Sstevel@tonic-gate 		new_cc.is_autopm_default = 1;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (uadmin(A_FREEZE, AD_CHECK, 0) == 0)
163*7c478bd9Sstevel@tonic-gate 		new_cc.is_cpr_capable = 1;
164*7c478bd9Sstevel@tonic-gate 	else
165*7c478bd9Sstevel@tonic-gate 		ua_err = errno;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/tod", O_RDONLY)) != -1) {
168*7c478bd9Sstevel@tonic-gate 		new_cc.is_autowakeup_capable = 1;
169*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate #endif /* sparc */
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	/*
174*7c478bd9Sstevel@tonic-gate 	 * Read in the cpr conf file.  If any open or read error occurs,
175*7c478bd9Sstevel@tonic-gate 	 * display an error message only for a non-root user.  The file
176*7c478bd9Sstevel@tonic-gate 	 * may not exist on a newly installed system.
177*7c478bd9Sstevel@tonic-gate 	 */
178*7c478bd9Sstevel@tonic-gate 	err_fmt = "%s %s; please rerun %s as root\n";
179*7c478bd9Sstevel@tonic-gate 	if ((fd = open(cpr_conf, O_RDONLY)) == -1) {
180*7c478bd9Sstevel@tonic-gate 		if (ruid)
181*7c478bd9Sstevel@tonic-gate 			mesg(MEXIT, err_fmt, gettext("cannot open"),
182*7c478bd9Sstevel@tonic-gate 			    cpr_conf, prog);
183*7c478bd9Sstevel@tonic-gate 	} else {
184*7c478bd9Sstevel@tonic-gate 		nread = read(fd, &disk_cc, sizeof (disk_cc));
185*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
186*7c478bd9Sstevel@tonic-gate 		if (nread != (ssize_t)sizeof (disk_cc)) {
187*7c478bd9Sstevel@tonic-gate 			if (ruid)
188*7c478bd9Sstevel@tonic-gate 				mesg(MEXIT, err_fmt, cpr_conf,
189*7c478bd9Sstevel@tonic-gate 				    gettext("file corrupted"), prog);
190*7c478bd9Sstevel@tonic-gate 			else {
191*7c478bd9Sstevel@tonic-gate 				(void) unlink(cpr_conf);
192*7c478bd9Sstevel@tonic-gate 				bzero(&disk_cc, sizeof (disk_cc));
193*7c478bd9Sstevel@tonic-gate 			}
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate  * Unconfigure and reset PM, device is left open for later use.
201*7c478bd9Sstevel@tonic-gate  */
202*7c478bd9Sstevel@tonic-gate static void
203*7c478bd9Sstevel@tonic-gate pm_rem_reset(void)
204*7c478bd9Sstevel@tonic-gate {
205*7c478bd9Sstevel@tonic-gate 	char *err_fmt = NULL;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	if ((pm_fd = open("/dev/pm", O_RDWR)) == -1)
208*7c478bd9Sstevel@tonic-gate 		err_fmt = "cannot open \"/dev/pm\": %s\n";
209*7c478bd9Sstevel@tonic-gate 	else if (ioctl(pm_fd, PM_RESET_PM, 0) == -1)
210*7c478bd9Sstevel@tonic-gate 		err_fmt = "cannot reset pm state: %s\n";
211*7c478bd9Sstevel@tonic-gate 	if (err_fmt)
212*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, err_fmt, strerror(errno));
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate static void
217*7c478bd9Sstevel@tonic-gate get_powerd_pid(void)
218*7c478bd9Sstevel@tonic-gate {
219*7c478bd9Sstevel@tonic-gate 	char pidstr[16];
220*7c478bd9Sstevel@tonic-gate 	int fd;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	if ((fd = open(PIDPATH, O_RDONLY)) == -1)
223*7c478bd9Sstevel@tonic-gate 		return;
224*7c478bd9Sstevel@tonic-gate 	bzero(pidstr, sizeof (pidstr));
225*7c478bd9Sstevel@tonic-gate 	if (read(fd, pidstr, sizeof (pidstr)) > 0) {
226*7c478bd9Sstevel@tonic-gate 		powerd_pid = atoi(pidstr);
227*7c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "got powerd pid %ld\n", powerd_pid);
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
230*7c478bd9Sstevel@tonic-gate }
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate /*
234*7c478bd9Sstevel@tonic-gate  * Write revised cprconfig struct to disk based on perms;
235*7c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
236*7c478bd9Sstevel@tonic-gate  */
237*7c478bd9Sstevel@tonic-gate static int
238*7c478bd9Sstevel@tonic-gate update_cprconfig(void)
239*7c478bd9Sstevel@tonic-gate {
240*7c478bd9Sstevel@tonic-gate 	struct cprconfig *wrt_cc = &new_cc;
241*7c478bd9Sstevel@tonic-gate 	char *err_fmt = NULL;
242*7c478bd9Sstevel@tonic-gate 	int fd;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	if (rflag) {
245*7c478bd9Sstevel@tonic-gate 		/* For "pmconfig -r" case, copy select cpr-related fields. */
246*7c478bd9Sstevel@tonic-gate 		new_cc.cf_magic = disk_cc.cf_magic;
247*7c478bd9Sstevel@tonic-gate 		new_cc.cf_type = disk_cc.cf_type;
248*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_path);
249*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_fs);
250*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_devfs);
251*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, cf_dev_prom);
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	if (!pm_status.perm) {
255*7c478bd9Sstevel@tonic-gate 		if (cpr_status.update == NOUP)
256*7c478bd9Sstevel@tonic-gate 			return (1);
257*7c478bd9Sstevel@tonic-gate 		/* save new struct data with old autopm setting */
258*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(new_cc, disk_cc, apm_behavior);
259*7c478bd9Sstevel@tonic-gate 	} else if (!cpr_status.perm) {
260*7c478bd9Sstevel@tonic-gate 		if (pm_status.update == NOUP)
261*7c478bd9Sstevel@tonic-gate 			return (1);
262*7c478bd9Sstevel@tonic-gate 		/* save original struct with new autopm setting */
263*7c478bd9Sstevel@tonic-gate 		MCCPY_FIELD(disk_cc, new_cc, apm_behavior);
264*7c478bd9Sstevel@tonic-gate 		wrt_cc = &disk_cc;
265*7c478bd9Sstevel@tonic-gate 	} else if (cpr_status.update == NOUP || pm_status.update == NOUP)
266*7c478bd9Sstevel@tonic-gate 		return (1);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	if ((fd = open(cpr_conf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1)
269*7c478bd9Sstevel@tonic-gate 		err_fmt = "cannot open/create \"%s\", %s\n";
270*7c478bd9Sstevel@tonic-gate 	else if (write(fd, wrt_cc, sizeof (*wrt_cc)) != sizeof (*wrt_cc))
271*7c478bd9Sstevel@tonic-gate 		err_fmt = "error writing \"%s\", %s\n";
272*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
273*7c478bd9Sstevel@tonic-gate 	if (err_fmt)
274*7c478bd9Sstevel@tonic-gate 		mesg(MERR, err_fmt, cpr_conf, strerror(errno));
275*7c478bd9Sstevel@tonic-gate 	return (err_fmt != NULL);
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * Signal old powerd when there's a valid pid, or start a new one;
281*7c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
282*7c478bd9Sstevel@tonic-gate  */
283*7c478bd9Sstevel@tonic-gate static int
284*7c478bd9Sstevel@tonic-gate restart_powerd(void)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	char *powerd = "/usr/lib/power/powerd";
287*7c478bd9Sstevel@tonic-gate 	int status = 0;
288*7c478bd9Sstevel@tonic-gate 	pid_t pid, wp;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	if (powerd_pid > 0) {
291*7c478bd9Sstevel@tonic-gate 		if (sigsend(P_PID, powerd_pid, SIGHUP) == 0)
292*7c478bd9Sstevel@tonic-gate 			return (0);
293*7c478bd9Sstevel@tonic-gate 		else if (errno != ESRCH) {
294*7c478bd9Sstevel@tonic-gate 			mesg(MERR, "cannot deliver hangup to powerd\n");
295*7c478bd9Sstevel@tonic-gate 			return (1);
296*7c478bd9Sstevel@tonic-gate 		}
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == NOPID)
300*7c478bd9Sstevel@tonic-gate 		wp = -1;
301*7c478bd9Sstevel@tonic-gate 	else if (pid == P_MYPID) {
302*7c478bd9Sstevel@tonic-gate 		(void) setreuid(0, 0);
303*7c478bd9Sstevel@tonic-gate 		(void) setregid(0, 0);
304*7c478bd9Sstevel@tonic-gate 		(void) setgroups(0, NULL);
305*7c478bd9Sstevel@tonic-gate 		(void) execle(powerd, powerd, NULL, NULL);
306*7c478bd9Sstevel@tonic-gate 		exit(1);
307*7c478bd9Sstevel@tonic-gate 	} else {
308*7c478bd9Sstevel@tonic-gate 		do {
309*7c478bd9Sstevel@tonic-gate 			wp = waitpid(pid, &status, 0);
310*7c478bd9Sstevel@tonic-gate 		} while (wp == -1 && errno == EINTR);
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	if (wp == -1)
314*7c478bd9Sstevel@tonic-gate 		mesg(MERR, "could not start %s\n", powerd);
315*7c478bd9Sstevel@tonic-gate 	return (wp == -1 || status != 0);
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate static void
320*7c478bd9Sstevel@tonic-gate save_orig(void)
321*7c478bd9Sstevel@tonic-gate {
322*7c478bd9Sstevel@tonic-gate 	static char *args[] = { "/usr/bin/cp", default_conf, orig_conf, NULL };
323*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
324*7c478bd9Sstevel@tonic-gate 	int pid;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	if (stat(orig_conf, &stbuf) == 0 && stbuf.st_size)
327*7c478bd9Sstevel@tonic-gate 		return;
328*7c478bd9Sstevel@tonic-gate 	pid = fork();
329*7c478bd9Sstevel@tonic-gate 	if (pid == NOPID)
330*7c478bd9Sstevel@tonic-gate 		return;
331*7c478bd9Sstevel@tonic-gate 	else if (pid == P_MYPID) {
332*7c478bd9Sstevel@tonic-gate 		(void) execve(args[0], args, NULL);
333*7c478bd9Sstevel@tonic-gate 		exit(1);
334*7c478bd9Sstevel@tonic-gate 	} else
335*7c478bd9Sstevel@tonic-gate 		(void) waitpid(pid, NULL, 0);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate static void
340*7c478bd9Sstevel@tonic-gate tmp_write(void *buf, size_t len)
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	if (write(tmp_fd, buf, len) != (ssize_t)len)
343*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "error writing tmp file, %s\n", strerror(errno));
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate static void
348*7c478bd9Sstevel@tonic-gate tmp_save_line(char *line, size_t len, cinfo_t *cip)
349*7c478bd9Sstevel@tonic-gate {
350*7c478bd9Sstevel@tonic-gate 	if (cip && cip->cmt)
351*7c478bd9Sstevel@tonic-gate 		tmp_write(cip->cmt, strlen(cip->cmt));
352*7c478bd9Sstevel@tonic-gate 	tmp_write(line, len);
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate /*
357*7c478bd9Sstevel@tonic-gate  * Filter conf lines and write them to the tmp file.
358*7c478bd9Sstevel@tonic-gate  */
359*7c478bd9Sstevel@tonic-gate static void
360*7c478bd9Sstevel@tonic-gate filter(char *line, size_t len, cinfo_t *cip)
361*7c478bd9Sstevel@tonic-gate {
362*7c478bd9Sstevel@tonic-gate 	int selected;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	/*
365*7c478bd9Sstevel@tonic-gate 	 * Lines from an alt conf file are selected when either:
366*7c478bd9Sstevel@tonic-gate 	 * cip is NULL (keyword not matched, probably an old-style device),
367*7c478bd9Sstevel@tonic-gate 	 * OR: it's both OK to accept the conf line (alt) AND either:
368*7c478bd9Sstevel@tonic-gate 	 * preference is not set (NULL checkup) OR the cpr/pm preference
369*7c478bd9Sstevel@tonic-gate 	 * (checkup) matches conftab status.
370*7c478bd9Sstevel@tonic-gate 	 */
371*7c478bd9Sstevel@tonic-gate 	selected = (cip == NULL || (cip->alt &&
372*7c478bd9Sstevel@tonic-gate 	    (checkup == NULL || checkup == cip->status)));
373*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "filter: set \"%s\", selected %d\n",
374*7c478bd9Sstevel@tonic-gate 	    cip ? cip->status->set : "none", selected);
375*7c478bd9Sstevel@tonic-gate 	if (selected)
376*7c478bd9Sstevel@tonic-gate 		tmp_save_line(line, len, cip);
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate /*
381*7c478bd9Sstevel@tonic-gate  * Set checkup for conf line selection and parse a conf file with filtering.
382*7c478bd9Sstevel@tonic-gate  * When pref is NULL, filter selects all conf lines from the new conf file;
383*7c478bd9Sstevel@tonic-gate  * otherwise filter selects only cpr or pm related lines from the new or
384*7c478bd9Sstevel@tonic-gate  * default conf file based on cpr or pm perm.
385*7c478bd9Sstevel@tonic-gate  */
386*7c478bd9Sstevel@tonic-gate static void
387*7c478bd9Sstevel@tonic-gate conf_scanner(prmup_t *pref)
388*7c478bd9Sstevel@tonic-gate {
389*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "\nscanning set is %s\n", pref ? pref->set : "both");
390*7c478bd9Sstevel@tonic-gate 	checkup = pref;
391*7c478bd9Sstevel@tonic-gate 	parse_conf_file((pref == NULL || pref->perm)
392*7c478bd9Sstevel@tonic-gate 	    ? power_conf : default_conf, filter);
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate /*
397*7c478bd9Sstevel@tonic-gate  * Search for any non-alt entries, call the handler routine,
398*7c478bd9Sstevel@tonic-gate  * and write entries to the tmp file.
399*7c478bd9Sstevel@tonic-gate  */
400*7c478bd9Sstevel@tonic-gate static void
401*7c478bd9Sstevel@tonic-gate search(char *line, size_t len, cinfo_t *cip)
402*7c478bd9Sstevel@tonic-gate {
403*7c478bd9Sstevel@tonic-gate 	int skip;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	skip = (cip == NULL || cip->alt);
406*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "search: %s\n", skip ? "skipped" : "retained");
407*7c478bd9Sstevel@tonic-gate 	if (skip)
408*7c478bd9Sstevel@tonic-gate 		return;
409*7c478bd9Sstevel@tonic-gate 	if (cip->status->perm)
410*7c478bd9Sstevel@tonic-gate 		(void) (*cip->handler)();
411*7c478bd9Sstevel@tonic-gate 	tmp_save_line(line, len, cip);
412*7c478bd9Sstevel@tonic-gate }
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate /*
416*7c478bd9Sstevel@tonic-gate  * When perm and update status are OK, write a new conf file
417*7c478bd9Sstevel@tonic-gate  * and rename to default_conf with the original attributes;
418*7c478bd9Sstevel@tonic-gate  * returns 1 if any error, otherwise 0.
419*7c478bd9Sstevel@tonic-gate  */
420*7c478bd9Sstevel@tonic-gate static int
421*7c478bd9Sstevel@tonic-gate write_conf(void)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	char *name, *err_str = NULL;
424*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if ((cpr_status.perm && cpr_status.update != OKUP) ||
427*7c478bd9Sstevel@tonic-gate 	    (pm_status.perm && pm_status.update != OKUP)) {
428*7c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\nconf not written, "
429*7c478bd9Sstevel@tonic-gate 		    "(cpr perm %d update %d), (pm perm %d update %d)\n",
430*7c478bd9Sstevel@tonic-gate 		    cpr_status.perm, cpr_status.update,
431*7c478bd9Sstevel@tonic-gate 		    pm_status.perm, pm_status.update);
432*7c478bd9Sstevel@tonic-gate 		return (1);
433*7c478bd9Sstevel@tonic-gate 	}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	save_orig();
436*7c478bd9Sstevel@tonic-gate 	if ((tmp_fd = mkstemp(tmp_conf)) == -1) {
437*7c478bd9Sstevel@tonic-gate 		mesg(MERR, "cannot open/create tmp file \"%s\"\n", tmp_conf);
438*7c478bd9Sstevel@tonic-gate 		return (1);
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 	tmp_write(conf_header, sizeof (conf_header) - 1);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	/*
443*7c478bd9Sstevel@tonic-gate 	 * When both perms are set, save selected lines from the new file;
444*7c478bd9Sstevel@tonic-gate 	 * otherwise save selected subsets from the new and default files.
445*7c478bd9Sstevel@tonic-gate 	 */
446*7c478bd9Sstevel@tonic-gate 	if (cpr_status.perm && pm_status.perm)
447*7c478bd9Sstevel@tonic-gate 		conf_scanner(NULL);
448*7c478bd9Sstevel@tonic-gate 	else {
449*7c478bd9Sstevel@tonic-gate 		conf_scanner(&cpr_status);
450*7c478bd9Sstevel@tonic-gate 		conf_scanner(&pm_status);
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	/*
454*7c478bd9Sstevel@tonic-gate 	 * "dtpower" will craft an alt conf file with modified content from
455*7c478bd9Sstevel@tonic-gate 	 * /etc/power.conf, but any alt conf file is not a trusted source;
456*7c478bd9Sstevel@tonic-gate 	 * since some alt conf lines may be skipped, the trusted source is
457*7c478bd9Sstevel@tonic-gate 	 * searched for those lines to retain their functionality.
458*7c478bd9Sstevel@tonic-gate 	 */
459*7c478bd9Sstevel@tonic-gate 	parse_conf_file(default_conf, search);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	if (stat(name = default_conf, &stbuf) == -1)
464*7c478bd9Sstevel@tonic-gate 		err_str = "stat";
465*7c478bd9Sstevel@tonic-gate 	else if (chmod(name = tmp_conf, stbuf.st_mode) == -1)
466*7c478bd9Sstevel@tonic-gate 		err_str = "chmod";
467*7c478bd9Sstevel@tonic-gate 	else if (chown(tmp_conf, stbuf.st_uid, stbuf.st_gid) == -1)
468*7c478bd9Sstevel@tonic-gate 		err_str = "chown";
469*7c478bd9Sstevel@tonic-gate 	else if (rename(tmp_conf, default_conf) == -1)
470*7c478bd9Sstevel@tonic-gate 		err_str = "rename";
471*7c478bd9Sstevel@tonic-gate 	else
472*7c478bd9Sstevel@tonic-gate 		mesg(MDEBUG, "\n\"%s\" renamed to \"%s\"\n",
473*7c478bd9Sstevel@tonic-gate 		    tmp_conf, default_conf);
474*7c478bd9Sstevel@tonic-gate 	if (err_str)
475*7c478bd9Sstevel@tonic-gate 		mesg(MERR, "cannot %s \"%s\", %s\n",
476*7c478bd9Sstevel@tonic-gate 		    err_str, name, strerror(errno));
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	return (err_str != NULL);
479*7c478bd9Sstevel@tonic-gate }
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
483*7c478bd9Sstevel@tonic-gate int
484*7c478bd9Sstevel@tonic-gate main(int cnt, char **vec)
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 	int rval = 0;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
489*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	for (prog = *vec++; *vec && **vec == '-'; vec++) {
492*7c478bd9Sstevel@tonic-gate 		if (strlen(*vec) > 2)
493*7c478bd9Sstevel@tonic-gate 			usage();
494*7c478bd9Sstevel@tonic-gate 		switch (*(*vec + 1)) {
495*7c478bd9Sstevel@tonic-gate 		case 'd':
496*7c478bd9Sstevel@tonic-gate 			debug = 1;
497*7c478bd9Sstevel@tonic-gate 			break;
498*7c478bd9Sstevel@tonic-gate 		case 'f':
499*7c478bd9Sstevel@tonic-gate 			fflag = 1;
500*7c478bd9Sstevel@tonic-gate 			if ((power_conf = *++vec) == NULL)
501*7c478bd9Sstevel@tonic-gate 				usage();
502*7c478bd9Sstevel@tonic-gate 			break;
503*7c478bd9Sstevel@tonic-gate 		case 'r':
504*7c478bd9Sstevel@tonic-gate 			rflag = 1;
505*7c478bd9Sstevel@tonic-gate 			break;
506*7c478bd9Sstevel@tonic-gate 		default:
507*7c478bd9Sstevel@tonic-gate 			usage();
508*7c478bd9Sstevel@tonic-gate 			break;
509*7c478bd9Sstevel@tonic-gate 		}
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 	if (rflag && fflag)
512*7c478bd9Sstevel@tonic-gate 		usage();
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	lookup_perms();
515*7c478bd9Sstevel@tonic-gate 	mesg(MDEBUG, "ruid %d, perms: cpr %d, pm %d\n",
516*7c478bd9Sstevel@tonic-gate 	    ruid, cpr_status.perm, pm_status.perm);
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	if ((!cpr_status.perm && !pm_status.perm) ||
519*7c478bd9Sstevel@tonic-gate 	    (rflag && !(cpr_status.perm && pm_status.perm)))
520*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "%s\n", strerror(EACCES));
521*7c478bd9Sstevel@tonic-gate 	if (rflag == 0 && access(power_conf, R_OK))
522*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "\"%s\" is not readable\n", power_conf);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	get_cpr_info();
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	if (pm_status.perm)
527*7c478bd9Sstevel@tonic-gate 		pm_rem_reset();
528*7c478bd9Sstevel@tonic-gate 	get_powerd_pid();
529*7c478bd9Sstevel@tonic-gate 	(void) umask(022);
530*7c478bd9Sstevel@tonic-gate 	if (rflag)
531*7c478bd9Sstevel@tonic-gate 		return (update_cprconfig() || restart_powerd());
532*7c478bd9Sstevel@tonic-gate 	if (stat(default_conf, &def_info) == -1)
533*7c478bd9Sstevel@tonic-gate 		mesg(MEXIT, "cannot stat %s, %s\n", default_conf,
534*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
535*7c478bd9Sstevel@tonic-gate 	new_cc.loadaverage_thold = DFLT_THOLD;
536*7c478bd9Sstevel@tonic-gate 	parse_conf_file(power_conf, NULL);
537*7c478bd9Sstevel@tonic-gate 	if (pm_status.perm)
538*7c478bd9Sstevel@tonic-gate 		(void) close(pm_fd);
539*7c478bd9Sstevel@tonic-gate 	if (fflag)
540*7c478bd9Sstevel@tonic-gate 		rval = write_conf();
541*7c478bd9Sstevel@tonic-gate 	cleanup();
542*7c478bd9Sstevel@tonic-gate 	if (rval == 0)
543*7c478bd9Sstevel@tonic-gate 		rval = (update_cprconfig() || restart_powerd());
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	return (rval);
546*7c478bd9Sstevel@tonic-gate }
547