xref: /illumos-gate/usr/src/cmd/power/powerd.c (revision 24f5a37652e188ebdcdd6da454511686935025df)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>			/* Standard */
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <time.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <pwd.h>
34 #include <dirent.h>
35 #include <thread.h>
36 #include <limits.h>
37 #include <sys/todio.h>			/* Time-Of-Day chip */
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40 #include <sys/ipc.h>			/* IPC functions */
41 #include <signal.h>			/* signal handling */
42 #include <syslog.h>
43 #include <unistd.h>
44 #include <libdevinfo.h>
45 #include <poll.h>
46 #include <sys/pm.h>			/* power management driver */
47 #include <sys/uadmin.h>
48 #include <sys/openpromio.h>		/* for prom access */
49 #include <sys/sysmacros.h>		/* for MIN & MAX macros */
50 #include <sys/modctl.h>
51 #include <sys/stropts.h>		/* for INFTIM */
52 #include <sys/pbio.h>
53 #include <sys/cpr.h>
54 #include <sys/srn.h>
55 #include <stdarg.h>
56 
57 #include "powerd.h"
58 
59 /* External Functions */
60 extern struct tm *localtime_r(const time_t *, struct tm *);
61 extern void sysstat_init(void);
62 extern int check_tty(hrtime_t *, int);
63 extern int check_disks(hrtime_t *, int);
64 extern int check_load_ave(hrtime_t *, float);
65 extern int check_nfs(hrtime_t *, int);
66 extern int last_disk_activity(hrtime_t *, int);
67 extern int last_tty_activity(hrtime_t *, int);
68 extern int last_load_ave_activity(hrtime_t *);
69 extern int last_nfs_activity(hrtime_t *, int);
70 
71 #define	PM		"/dev/pm"
72 #define	TOD		"/dev/tod"
73 #define	PROM		"/dev/openprom"
74 #define	PB		"/dev/power_button"
75 #define	SRN		"/dev/srn"
76 #define	LOGFILE		"./powerd.log"
77 
78 #define	PBM_THREAD	0
79 #define	ATTACH_THREAD	1
80 #define	NUM_THREADS	2
81 
82 #define	CHECK_INTERVAL	5
83 #define	IDLECHK_INTERVAL	15
84 #define	MINS_TO_SECS	60
85 #define	HOURS_TO_SECS	(60 * 60)
86 #define	DAYS_TO_SECS	(24 * 60 * 60)
87 #define	HOURS_TO_MINS	60
88 #define	DAYS_TO_MINS	(24 * 60)
89 
90 #define	LIFETIME_SECS			(7 * 365 * DAYS_TO_SECS)
91 #define	DEFAULT_POWER_CYCLE_LIMIT	10000
92 #define	DEFAULT_SYSTEM_BOARD_DATE	804582000	/* July 1, 1995 */
93 
94 #define	LLEN 80
95 
96 typedef	enum {root, options} prom_node_t;
97 
98 /* State Variables */
99 static struct cprconfig	asinfo;
100 static time_t		shutdown_time;	/* Time for next shutdown check */
101 static time_t		checkidle_time;	/* Time for next idleness check */
102 static time_t		last_resume;
103 pwr_info_t		*info;		/* private as config data buffer */
104 static int		pb_fd;		/* power button driver */
105 static int		broadcast;	/* Enables syslog messages */
106 static int		start_calc;
107 static int		autoshutdown_en;
108 static int		do_idlecheck;
109 static int		got_sighup;
110 static int		estar_v2_prop;
111 static int		estar_v3_prop;
112 static int		log_power_cycles_error = 0;
113 static int		log_system_board_date_error = 0;
114 static int		log_no_autoshutdown_warning = 0;
115 static mutex_t		poweroff_mutex;
116 
117 static char *autoshutdown_cmd[] = {
118 	"/usr/bin/sys-suspend",
119 	"-n", "-d", ":0", NULL
120 };
121 
122 static char *power_button_cmd[] = {
123 	"/usr/bin/sys-suspend",
124 	"-h", "-d", ":0", NULL
125 };
126 
127 static char *autoS3_cmd[] = {
128 	"/usr/bin/sys-suspend",
129 	"-n", "-d", ":0", NULL
130 };
131 
132 static char pidpath[] = PIDPATH;
133 static char scratch[PATH_MAX];
134 static char *prog;
135 
136 /* Local Functions */
137 static void alarm_handler(int);
138 static void thaw_handler(int);
139 static void kill_handler(int);
140 static void work_handler(int);
141 static void check_shutdown(time_t *, hrtime_t *);
142 static void check_idleness(time_t *, hrtime_t *);
143 static int last_system_activity(hrtime_t *);
144 static int run_idlecheck(void);
145 static void set_alarm(time_t);
146 static int poweroff(const char *, char **);
147 static int is_ok2shutdown(time_t *);
148 static int get_prom(int, prom_node_t, char *, char *, size_t);
149 static void power_button_monitor(void *);
150 static int open_pidfile(char *);
151 static int write_pidfile(int, pid_t);
152 static int read_cpr_config(void);
153 static void system_activity_monitor(void);
154 static void autos3_monitor(void);
155 static void do_attach(void);
156 static void *attach_devices(void *);
157 static int powerd_debug;
158 
159 /* PRINTFLIKE1 */
160 static void
161 logerror(const char *fmt, ...)
162 {
163 	va_list args;
164 
165 	va_start(args, fmt);
166 	if (broadcast)
167 		vsyslog(LOG_ERR, fmt, args);
168 	va_end(args);
169 }
170 
171 
172 static void
173 estrcpy(char *dst, char *src, size_t dlen)
174 {
175 	size_t slen;
176 
177 	slen = strlcpy(dst, src, dlen);
178 	if (slen >= dlen) {
179 		logerror("%s: string too long \"%s ...\"\n"
180 		    "(len %d, max %d)\n", prog, dst, slen, dlen - 1);
181 		exit(EXIT_FAILURE);
182 	}
183 }
184 
185 
186 int
187 main(int argc, char *argv[])
188 {
189 	pid_t		pid;
190 	int		pm_fd;
191 	struct sigaction act;
192 	sigset_t	sigmask;
193 	int		c;
194 	char		errmsg[PATH_MAX + 64];
195 	int		pid_fd;
196 
197 	prog = argv[0];
198 	if (geteuid() != 0) {
199 		(void) fprintf(stderr, "%s: Must be root\n", prog);
200 		exit(EXIT_FAILURE);
201 	}
202 
203 	if ((pid_fd = open_pidfile(prog)) ==  -1)
204 		exit(EXIT_FAILURE);
205 
206 	/*
207 	 * Process options
208 	 */
209 	broadcast = 1;
210 	while ((c = getopt(argc, argv, "nd")) != EOF) {
211 		switch (c) {
212 		case 'd':
213 			powerd_debug = 1;
214 			break;
215 		case 'n':
216 			broadcast = 0;
217 			break;
218 		case '?':
219 			(void) fprintf(stderr, "Usage: %s [-n]\n", prog);
220 			exit(EXIT_FAILURE);
221 		}
222 	}
223 
224 	pm_fd = open(PM, O_RDWR);
225 	if (pm_fd == -1) {
226 		(void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM);
227 		perror(errmsg);
228 		exit(EXIT_FAILURE);
229 	}
230 	(void) close(pm_fd);
231 
232 	/*
233 	 * Initialize mutex lock used to insure only one command to
234 	 * run at a time.
235 	 */
236 	if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) {
237 		(void) fprintf(stderr,
238 		    "%s: Unable to initialize mutex lock\n", prog);
239 		exit(EXIT_FAILURE);
240 	}
241 
242 	if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) {
243 		(void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog);
244 		perror(errmsg);
245 		exit(EXIT_FAILURE);
246 	}
247 
248 	/*
249 	 * Daemon is set to go...
250 	 */
251 	if ((pid = fork()) < 0)
252 		exit(EXIT_FAILURE);
253 	else if (pid != 0)
254 		exit(EXIT_SUCCESS);
255 
256 	pid = getpid();
257 	openlog(prog, 0, LOG_DAEMON);
258 	if (write_pidfile(pid_fd, pid) == -1)	/* logs errors on failure */
259 		exit(EXIT_FAILURE);
260 	(void) close(pid_fd);
261 
262 	/*
263 	 * Close all the parent's file descriptors (Bug 1225843).
264 	 */
265 	closefrom(0);
266 	(void) setsid();
267 	(void) chdir("/");
268 	(void) umask(0);
269 #ifdef DEBUG
270 	/*
271 	 * Connect stdout to the console.
272 	 */
273 	if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) {
274 		logerror("Unable to connect to the console.");
275 	}
276 #endif
277 	info->pd_flags = PD_AC;
278 	info->pd_idle_time = -1;
279 	info->pd_start_time = 0;
280 	info->pd_finish_time = 0;
281 
282 	/*
283 	 * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
284 	 * any time
285 	 */
286 	act.sa_handler = kill_handler;
287 	(void) sigemptyset(&act.sa_mask);
288 	act.sa_flags = 0;
289 	(void) sigaction(SIGQUIT, &act, NULL);
290 	(void) sigaction(SIGINT, &act, NULL);
291 	(void) sigaction(SIGTERM, &act, NULL);
292 
293 	(void) sigfillset(&sigmask);
294 	(void) sigdelset(&sigmask, SIGQUIT);
295 	(void) sigdelset(&sigmask, SIGINT);
296 	(void) sigdelset(&sigmask, SIGTERM);
297 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
298 
299 	/*
300 	 * If "power_button" device node can be opened, create a new
301 	 * thread to monitor the power button.
302 	 */
303 	if ((pb_fd = open(PB, O_RDONLY)) != -1) {
304 		if (powerd_debug)
305 			logerror("powerd starting power button monitor.");
306 		if (thr_create(NULL, NULL,
307 		    (void *(*)(void *))power_button_monitor, NULL,
308 		    THR_DAEMON, NULL) != 0) {
309 			logerror("Unable to monitor system's power button.");
310 		}
311 	}
312 
313 	do_attach();
314 
315 	/*
316 	 * Create a new thread to monitor system activity and suspend
317 	 * system if idle.
318 	 */
319 	if (powerd_debug)
320 		logerror("powerd starting system activity monitor.");
321 	if (thr_create(NULL, NULL,
322 	    (void *(*)(void *))system_activity_monitor, NULL,
323 	    THR_DAEMON, NULL) != 0) {
324 		logerror("Unable to create thread to monitor system activity.");
325 	}
326 
327 	/*
328 	 * Create a new thread to handle autos3 trigger
329 	 */
330 	if (powerd_debug)
331 		logerror("powerd starting autos3 monitor.");
332 	if (thr_create(NULL, NULL,
333 	    (void *(*)(void *))autos3_monitor, NULL, THR_DAEMON, NULL) != 0) {
334 		logerror("Unable to create thread to monitor autos3 activity.");
335 	}
336 
337 	/*
338 	 * Block until we receive an explicit terminate signal
339 	 */
340 	(void) sigsuspend(&sigmask);
341 
342 	return (1);
343 }
344 
345 static void
346 system_activity_monitor(void)
347 {
348 	struct sigaction act;
349 	sigset_t sigmask;
350 
351 	/*
352 	 * Setup for gathering system's statistic.
353 	 */
354 	sysstat_init();
355 
356 	/*
357 	 * In addition to the SIGQUIT, SIGINT and SIGTERM signals already
358 	 * being handled, this thread also needs to handle SIGHUP, SIGALRM
359 	 * and SIGTHAW signals.
360 	 */
361 	(void) sigemptyset(&act.sa_mask);
362 	act.sa_flags = 0;
363 	act.sa_handler = alarm_handler;
364 	(void) sigaction(SIGALRM, &act, NULL);
365 	act.sa_handler = work_handler;
366 	(void) sigaction(SIGHUP, &act, NULL);
367 	act.sa_handler = thaw_handler;
368 	(void) sigaction(SIGTHAW, &act, NULL);
369 
370 	/*
371 	 * Invoke work_handler with a dummy SIGHUP signal to read
372 	 * cpr config file, get autoshutdown properties and schedule
373 	 * an alarm if needed.
374 	 */
375 	work_handler(SIGHUP);
376 
377 	/*
378 	 * Wait for signal to read file
379 	 */
380 	(void) thr_sigsetmask(0, 0, &sigmask);
381 	(void) sigdelset(&sigmask, SIGHUP);
382 	(void) sigdelset(&sigmask, SIGALRM);
383 	(void) sigdelset(&sigmask, SIGTHAW);
384 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
385 	do {
386 		(void) sigsuspend(&sigmask);
387 	} while (errno == EINTR);
388 }
389 
390 static void
391 autos3_monitor(void)
392 {
393 	struct pollfd poll_fd;
394 	srn_event_info_t srn_event;		/* contains suspend type */
395 	int fd, ret;
396 
397 	fd = open(SRN, O_RDWR|O_EXCL|O_NDELAY);
398 	if (fd == -1) {
399 		logerror("Unable to open %s: %s", SRN, strerror(errno));
400 		thr_exit((void *)(intptr_t)errno);
401 	}
402 
403 	/*
404 	 * Tell device we want the special sauce
405 	 */
406 	ret = ioctl(fd, SRN_IOC_AUTOSX, NULL);
407 	if (ret == -1) {
408 		logerror("Ioctl SRN_IOC_AUTOSX failed: %s", strerror(errno));
409 		(void) close(fd);
410 		thr_exit((void *)(intptr_t)errno);
411 	}
412 	poll_fd.fd = fd;
413 	/*CONSTCOND*/
414 	while (1) {
415 		poll_fd.revents = 0;
416 		poll_fd.events = POLLIN;
417 		if (poll(&poll_fd, 1, -1) < 0) {
418 			switch (errno) {
419 			case EINTR:
420 			case EAGAIN:
421 				continue;
422 			default:
423 				logerror("Poll error: %s", strerror(errno));
424 				(void) close(fd);
425 				thr_exit((void *)(intptr_t)errno);
426 			}
427 		}
428 
429 		ret = ioctl(fd, SRN_IOC_NEXTEVENT, &srn_event);
430 		if (ret == -1) {
431 			logerror("ioctl error: %s", strerror(errno));
432 			(void) close(fd);
433 			thr_exit((void *)(intptr_t)errno);
434 		}
435 		switch (srn_event.ae_type) {
436 		case 3:			/* S3 */
437 			if (powerd_debug)
438 				logerror("ioctl returns type: %d",
439 				    srn_event.ae_type);
440 			break;
441 		default:
442 			logerror("Unsupported target state %d",
443 			    srn_event.ae_type);
444 			continue;
445 		}
446 		(void) poweroff("AutoS3", autoS3_cmd);
447 		continue;
448 	}
449 }
450 
451 static int
452 read_cpr_config(void)
453 {
454 	int	asfd;
455 
456 	if ((asfd = open(CPR_CONFIG, O_RDONLY)) < 0) {
457 		logerror("Unable to open CPR config file '%s'", CPR_CONFIG);
458 		return (-1);
459 	}
460 
461 	if (read(asfd, (void *)&asinfo, sizeof (asinfo)) != sizeof (asinfo)) {
462 		logerror("Unable to read CPR config file '%s'", CPR_CONFIG);
463 		(void) close(asfd);
464 		return (-1);
465 	}
466 
467 	(void) close(asfd);
468 
469 	return (0);
470 }
471 
472 /*ARGSUSED*/
473 static void
474 thaw_handler(int sig)
475 {
476 	start_calc  = 0;
477 	last_resume = time(NULL);
478 }
479 
480 /*ARGSUSED*/
481 static void
482 kill_handler(int sig)
483 {
484 	int ret_code = EXIT_SUCCESS;
485 
486 	/*
487 	 * Free resources
488 	 */
489 
490 	free(info);
491 	if (pb_fd != -1) {
492 		(void) close(pb_fd);
493 	}
494 	(void) mutex_destroy(&poweroff_mutex);
495 	(void) unlink(pidpath);
496 	closelog();
497 	exit(ret_code);
498 }
499 
500 /*ARGSUSED*/
501 static void
502 alarm_handler(int sig)
503 {
504 	time_t		now;
505 	hrtime_t	hr_now;
506 
507 	now = time(NULL);
508 	hr_now = gethrtime();
509 	if (checkidle_time <= now && checkidle_time != 0)
510 		check_idleness(&now, &hr_now);
511 	if (shutdown_time <= now && shutdown_time != 0)
512 		check_shutdown(&now, &hr_now);
513 
514 	set_alarm(now);
515 }
516 
517 /*ARGSUSED*/
518 static void
519 work_handler(int sig)
520 {
521 	time_t		now;
522 	hrtime_t	hr_now;
523 	struct stat	stat_buf;
524 
525 	do_idlecheck = 0;
526 	info->pd_flags = PD_AC;
527 
528 	/*
529 	 * Parse the config file for autoshutdown and idleness entries.
530 	 */
531 	if (read_cpr_config() < 0)
532 		return;
533 
534 	/*
535 	 * Since Oct. 1, 1995, any new system shipped had root
536 	 * property "energystar-v2" defined in its prom.  Systems
537 	 * shipped after July 1, 1999, will have "energystar-v3"
538 	 * property.
539 	 */
540 	estar_v2_prop = asinfo.is_cpr_default;
541 
542 	info->pd_flags |= asinfo.is_autowakeup_capable;
543 
544 	if (strlen(asinfo.idlecheck_path) > 0) {
545 		if (stat(asinfo.idlecheck_path, &stat_buf) != 0) {
546 			logerror("unable to access idlecheck program \"%s\".",
547 			    asinfo.idlecheck_path);
548 		} else if (!(stat_buf.st_mode & S_IXUSR)) {
549 			logerror("idlecheck program \"%s\" is not executable.",
550 			    asinfo.idlecheck_path);
551 		} else {
552 			do_idlecheck = 1;
553 		}
554 	}
555 
556 	if (strlen(asinfo.as_behavior) == 0 ||
557 	    strcmp(asinfo.as_behavior, "noshutdown") == 0 ||
558 	    strcmp(asinfo.as_behavior, "unconfigured") == 0) {
559 		info->pd_autoshutdown = 0;
560 	} else if (strcmp(asinfo.as_behavior, "default") == 0) {
561 		info->pd_autoshutdown = estar_v2_prop;
562 	} else if (strcmp(asinfo.as_behavior, "shutdown") == 0 ||
563 	    strcmp(asinfo.as_behavior, "autowakeup") == 0) {
564 		info->pd_autoshutdown = asinfo.is_cpr_capable;
565 	} else {
566 		logerror("autoshutdown behavior \"%s\" unrecognized.",
567 		    asinfo.as_behavior);
568 		info->pd_autoshutdown = 0;
569 	}
570 
571 	if (info->pd_autoshutdown) {
572 		info->pd_idle_time = asinfo.as_idle;
573 		info->pd_start_time =
574 		    (asinfo.as_sh * 60 + asinfo.as_sm) % DAYS_TO_MINS;
575 		info->pd_finish_time =
576 		    (asinfo.as_fh * 60 + asinfo.as_fm) % DAYS_TO_MINS;
577 		info->pd_autoresume =
578 		    (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0;
579 	}
580 	autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown)
581 	    ? 1 : 0;
582 
583 #ifdef DEBUG
584 	(void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, "
585 	    "pd_autoresume = %d\n",
586 	    autoshutdown_en, asinfo.as_idle, info->pd_autoresume);
587 
588 	(void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n",
589 	    info->pd_start_time, info->pd_finish_time);
590 #endif
591 
592 	got_sighup = 1;
593 	now = last_resume = time(NULL);
594 	hr_now = gethrtime();
595 	check_idleness(&now, &hr_now);
596 	check_shutdown(&now, &hr_now);
597 	set_alarm(now);
598 }
599 
600 static void
601 check_shutdown(time_t *now, hrtime_t *hr_now)
602 {
603 	int		tod_fd = -1;
604 	int		kbd, mouse, system, least_idle, idlecheck_time;
605 	int		next_time;
606 	int		s, f;
607 	struct tm	tmp_time;
608 	time_t		start_of_day, time_since_last_resume;
609 	time_t		wakeup_time;
610 	extern long	conskbd_idle_time(void);
611 	extern long	consms_idle_time(void);
612 	static int	warned_kbd, warned_ms; /* print error msg one time */
613 
614 	if (!autoshutdown_en) {
615 		shutdown_time = 0;
616 		return;
617 	}
618 
619 	(void) localtime_r(now, &tmp_time);
620 	tmp_time.tm_sec = 0;
621 	tmp_time.tm_min = 0;
622 	tmp_time.tm_hour = 0;
623 	start_of_day = mktime(&tmp_time);
624 	s = start_of_day + info->pd_start_time * 60;
625 	f = start_of_day + info->pd_finish_time * 60;
626 	if ((s < f && *now >= s && *now < f) ||
627 	    (s >= f && (*now < f || *now >= s))) {
628 		if ((mouse = (int)consms_idle_time()) < 0) {
629 			if (! warned_ms) {
630 				warned_ms = 1;
631 				logerror("powerd: failed to get "
632 				    "idle time for console mouse");
633 			}
634 			return;
635 		}
636 		if ((kbd = (int)conskbd_idle_time()) < 0) {
637 			if (! warned_kbd) {
638 				warned_kbd = 1;
639 				logerror("powerd: failed to get "
640 				    "idle time for console keyboard");
641 			}
642 			return;
643 		}
644 
645 		system = last_system_activity(hr_now);
646 		/* who is the last to go idle */
647 		least_idle = MIN(system, MIN(kbd, mouse));
648 
649 		/*
650 		 * Calculate time_since_last_resume and the next_time
651 		 * to auto suspend.
652 		 */
653 		start_calc = 1;
654 		time_since_last_resume = time(NULL) - last_resume;
655 		next_time = info->pd_idle_time * 60 -
656 		    MIN(least_idle, time_since_last_resume);
657 
658 #ifdef DEBUG
659 		fprintf(stderr, " check_shutdown: next_time=%d\n", next_time);
660 #endif
661 
662 		/*
663 		 * If we have get the SIGTHAW signal at this point - our
664 		 * calculation of time_since_last_resume is wrong  so
665 		 * - we need to recalculate.
666 		 */
667 		while (start_calc == 0) {
668 			/* need to redo calculation */
669 			start_calc = 1;
670 			time_since_last_resume = time(NULL) - last_resume;
671 			next_time = info->pd_idle_time * 60 -
672 			    MIN(least_idle, time_since_last_resume);
673 		}
674 
675 		/*
676 		 * Only when everything else is idle, run the user's idlecheck
677 		 * script.
678 		 */
679 		if (next_time <= 0 && do_idlecheck) {
680 			got_sighup = 0;
681 			idlecheck_time = run_idlecheck();
682 			next_time = info->pd_idle_time * 60 -
683 			    MIN(idlecheck_time, MIN(least_idle,
684 			    time_since_last_resume));
685 			/*
686 			 * If we have caught SIGTHAW or SIGHUP, need to
687 			 * recalculate.
688 			 */
689 			while (start_calc == 0 || got_sighup == 1) {
690 				start_calc = 1;
691 				got_sighup = 0;
692 				idlecheck_time = run_idlecheck();
693 				time_since_last_resume = time(NULL) -
694 				    last_resume;
695 				next_time = info->pd_idle_time * 60 -
696 				    MIN(idlecheck_time, MIN(least_idle,
697 				    time_since_last_resume));
698 			}
699 		}
700 
701 		if (next_time <= 0) {
702 			if (is_ok2shutdown(now)) {
703 				/*
704 				 * Setup the autowakeup alarm.  Clear it
705 				 * right after poweroff, just in case if
706 				 * shutdown doesn't go through.
707 				 */
708 				if (info->pd_autoresume)
709 					tod_fd = open(TOD, O_RDWR);
710 				if (info->pd_autoresume && tod_fd != -1) {
711 					wakeup_time = (*now < f) ? f :
712 					    (f + DAYS_TO_SECS);
713 					/*
714 					 * A software fix for hardware
715 					 * bug 1217415.
716 					 */
717 					if ((wakeup_time - *now) < 180) {
718 						logerror(
719 		"Since autowakeup time is less than 3 minutes away, "
720 		"autoshutdown will not occur.");
721 						shutdown_time = *now + 180;
722 						(void) close(tod_fd);
723 						return;
724 					}
725 					if (ioctl(tod_fd, TOD_SET_ALARM,
726 					    &wakeup_time) == -1) {
727 						logerror("Unable to program TOD"
728 						    " alarm for autowakeup.");
729 						(void) close(tod_fd);
730 						return;
731 					}
732 				}
733 
734 				(void) poweroff("Autoshutdown",
735 				    autoshutdown_cmd);
736 
737 				if (info->pd_autoresume && tod_fd != -1) {
738 					if (ioctl(tod_fd, TOD_CLEAR_ALARM,
739 					    NULL) == -1)
740 						logerror("Unable to clear "
741 						    "alarm in TOD device.");
742 					(void) close(tod_fd);
743 				}
744 
745 				(void) time(now);
746 				/* wait at least 5 mins */
747 				shutdown_time = *now +
748 				    ((info->pd_idle_time * 60) > 300 ?
749 				    (info->pd_idle_time * 60) : 300);
750 			} else {
751 				/* wait 5 mins */
752 				shutdown_time = *now + 300;
753 			}
754 		} else
755 			shutdown_time = *now + next_time;
756 	} else if (s < f && *now >= f) {
757 		shutdown_time = s + DAYS_TO_SECS;
758 	} else
759 		shutdown_time = s;
760 }
761 
762 static int
763 is_ok2shutdown(time_t *now)
764 {
765 	int	prom_fd = -1;
766 	char	power_cycles_st[LLEN];
767 	char	power_cycle_limit_st[LLEN];
768 	char	system_board_date_st[LLEN];
769 	int	power_cycles, power_cycle_limit, free_cycles, scaled_cycles;
770 	time_t	life_began, life_passed;
771 	int	no_power_cycles = 0;
772 	int	no_system_board_date = 0;
773 	int	ret = 1;
774 
775 	/* CONSTCOND */
776 	while (1) {
777 		if ((prom_fd = open(PROM, O_RDWR)) == -1 &&
778 		    (errno == EAGAIN))
779 			continue;
780 		break;
781 	}
782 
783 	/*
784 	 * when #power-cycles property does not exist
785 	 * power cycles are unlimited.
786 	 */
787 	if (get_prom(prom_fd, options, "#power-cycles",
788 	    power_cycles_st, sizeof (power_cycles_st)) == 0)
789 		goto ckdone;
790 
791 	if (get_prom(prom_fd, root, "power-cycle-limit",
792 	    power_cycle_limit_st, sizeof (power_cycle_limit_st)) == 0) {
793 		power_cycle_limit = DEFAULT_POWER_CYCLE_LIMIT;
794 	} else {
795 		power_cycle_limit = atoi(power_cycle_limit_st);
796 	}
797 
798 	/*
799 	 * Allow 10% of power_cycle_limit as free cycles.
800 	 */
801 	free_cycles = power_cycle_limit / 10;
802 
803 	power_cycles = atoi(power_cycles_st);
804 	if (power_cycles < 0)
805 		no_power_cycles++;
806 	else if (power_cycles <= free_cycles)
807 		goto ckdone;
808 
809 	if (no_power_cycles && log_power_cycles_error == 0) {
810 		logerror("Invalid PROM property \"#power-cycles\" was found.");
811 		log_power_cycles_error++;
812 	}
813 
814 	if (get_prom(prom_fd, options, "system-board-date",
815 	    system_board_date_st, sizeof (system_board_date_st)) == 0) {
816 		no_system_board_date++;
817 	} else {
818 		life_began = strtol(system_board_date_st, (char **)NULL, 16);
819 		if (life_began > *now) {
820 			no_system_board_date++;
821 		}
822 	}
823 	if (no_system_board_date) {
824 		if (log_system_board_date_error == 0) {
825 			logerror("No or invalid PROM property "
826 			    "\"system-board-date\" was found.");
827 			log_system_board_date_error++;
828 		}
829 		life_began = DEFAULT_SYSTEM_BOARD_DATE;
830 	}
831 
832 	life_passed = *now - life_began;
833 
834 	/*
835 	 * Since we don't keep the date that last free_cycle is ended, we
836 	 * need to spread (power_cycle_limit - free_cycles) over the entire
837 	 * 7-year life span instead of (lifetime - date free_cycles ended).
838 	 */
839 	scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) *
840 	    (power_cycle_limit - free_cycles));
841 
842 	if (no_power_cycles)
843 		goto ckdone;
844 
845 #ifdef DEBUG
846 	(void) fprintf(stderr, "Actual power_cycles = %d\t"
847 	    "Scaled power_cycles = %d\n", power_cycles, scaled_cycles);
848 #endif
849 	if (power_cycles > scaled_cycles) {
850 		if (log_no_autoshutdown_warning == 0) {
851 			logerror("Automatic shutdown has been temporarily "
852 			    "suspended in order to preserve the reliability "
853 			    "of this system.");
854 			log_no_autoshutdown_warning++;
855 		}
856 		ret = 0;
857 		goto ckdone;
858 	}
859 
860 ckdone:
861 	if (prom_fd != -1)
862 		(void) close(prom_fd);
863 	return (ret);
864 }
865 
866 static void
867 check_idleness(time_t *now, hrtime_t *hr_now)
868 {
869 
870 	/*
871 	 * Check idleness only when autoshutdown is enabled.
872 	 */
873 	if (!autoshutdown_en) {
874 		checkidle_time = 0;
875 		return;
876 	}
877 
878 	info->pd_ttychars_idle = check_tty(hr_now, asinfo.ttychars_thold);
879 	info->pd_loadaverage_idle =
880 	    check_load_ave(hr_now, asinfo.loadaverage_thold);
881 	info->pd_diskreads_idle = check_disks(hr_now, asinfo.diskreads_thold);
882 	info->pd_nfsreqs_idle = check_nfs(hr_now, asinfo.nfsreqs_thold);
883 
884 #ifdef DEBUG
885 	(void) fprintf(stderr, "Idle ttychars for %d secs.\n",
886 	    info->pd_ttychars_idle);
887 	(void) fprintf(stderr, "Idle loadaverage for %d secs.\n",
888 	    info->pd_loadaverage_idle);
889 	(void) fprintf(stderr, "Idle diskreads for %d secs.\n",
890 	    info->pd_diskreads_idle);
891 	(void) fprintf(stderr, "Idle nfsreqs for %d secs.\n",
892 	    info->pd_nfsreqs_idle);
893 #endif
894 
895 	checkidle_time = *now + IDLECHK_INTERVAL;
896 }
897 
898 static int
899 last_system_activity(hrtime_t *hr_now)
900 {
901 	int	act_idle, latest;
902 
903 	latest = info->pd_idle_time * 60;
904 	act_idle = last_tty_activity(hr_now, asinfo.ttychars_thold);
905 	latest = MIN(latest, act_idle);
906 	act_idle = last_load_ave_activity(hr_now);
907 	latest = MIN(latest, act_idle);
908 	act_idle = last_disk_activity(hr_now, asinfo.diskreads_thold);
909 	latest = MIN(latest, act_idle);
910 	act_idle = last_nfs_activity(hr_now, asinfo.nfsreqs_thold);
911 	latest = MIN(latest, act_idle);
912 
913 	return (latest);
914 }
915 
916 static int
917 run_idlecheck()
918 {
919 	char		pm_variable[LLEN];
920 	char		*cp;
921 	int		status;
922 	pid_t		child;
923 
924 	/*
925 	 * Reap any child process which has been left over.
926 	 */
927 	while (waitpid((pid_t)-1, &status, WNOHANG) > 0)
928 		;
929 
930 	/*
931 	 * Execute the user's idlecheck script and set variable PM_IDLETIME.
932 	 * Returned exit value is the idle time in minutes.
933 	 */
934 	if ((child = fork1()) == 0) {
935 		(void) sprintf(pm_variable, "PM_IDLETIME=%d",
936 		    info->pd_idle_time);
937 		(void) putenv(pm_variable);
938 		cp = strrchr(asinfo.idlecheck_path, '/');
939 		if (cp == NULL)
940 			cp = asinfo.idlecheck_path;
941 		else
942 			cp++;
943 		(void) execl(asinfo.idlecheck_path, cp, NULL);
944 		exit(-1);
945 	} else if (child == -1) {
946 		return (info->pd_idle_time * 60);
947 	}
948 
949 	/*
950 	 * Wait until the idlecheck program completes.
951 	 */
952 	if (waitpid(child, &status, 0) != child) {
953 		/*
954 		 * We get here if the calling process gets a signal.
955 		 */
956 		return (info->pd_idle_time * 60);
957 	}
958 
959 	if (WEXITSTATUS(status) < 0) {
960 		return (info->pd_idle_time * 60);
961 	} else {
962 		return (WEXITSTATUS(status) * 60);
963 	}
964 }
965 
966 static void
967 set_alarm(time_t now)
968 {
969 	time_t	itime, stime, next_time, max_time;
970 	int	next_alarm;
971 
972 	max_time = MAX(checkidle_time, shutdown_time);
973 	if (max_time == 0) {
974 		(void) alarm(0);
975 		return;
976 	}
977 	itime = (checkidle_time == 0) ? max_time : checkidle_time;
978 	stime = (shutdown_time == 0) ? max_time : shutdown_time;
979 	next_time = MIN(itime, stime);
980 	next_alarm = (next_time <= now) ? 1 : (next_time - now);
981 	(void) alarm(next_alarm);
982 
983 #ifdef DEBUG
984 	(void) fprintf(stderr, "Currently @ %s", ctime(&now));
985 	(void) fprintf(stderr, "Checkidle in %d secs\n", checkidle_time - now);
986 	(void) fprintf(stderr, "Shutdown  in %d secs\n", shutdown_time - now);
987 	(void) fprintf(stderr, "Next alarm goes off in %d secs\n", next_alarm);
988 	(void) fprintf(stderr, "************************************\n");
989 #endif
990 }
991 
992 static int
993 poweroff(const char *msg, char **cmd_argv)
994 {
995 	struct stat	statbuf;
996 	pid_t		pid, child;
997 	struct passwd	*pwd;
998 	char		*home, *user;
999 	char		ehome[] = "HOME=";
1000 	char		euser[] = "LOGNAME=";
1001 	int		status;
1002 	char		**ca;
1003 
1004 	if (mutex_trylock(&poweroff_mutex) != 0)
1005 		return (0);
1006 
1007 	if (stat("/dev/console", &statbuf) == -1 ||
1008 	    (pwd = getpwuid(statbuf.st_uid)) == NULL) {
1009 		(void) mutex_unlock(&poweroff_mutex);
1010 		return (1);
1011 	}
1012 
1013 	if (msg)
1014 		syslog(LOG_NOTICE, msg);
1015 
1016 	if (*cmd_argv == NULL) {
1017 		logerror("No command to run.");
1018 		(void) mutex_unlock(&poweroff_mutex);
1019 		return (1);
1020 	}
1021 
1022 	home = malloc(strlen(pwd->pw_dir) + sizeof (ehome));
1023 	user = malloc(strlen(pwd->pw_name) + sizeof (euser));
1024 	if (home == NULL || user == NULL) {
1025 		free(home);
1026 		free(user);
1027 		logerror("No memory.");
1028 		(void) mutex_unlock(&poweroff_mutex);
1029 		return (1);
1030 	}
1031 	(void) strcpy(home, ehome);
1032 	(void) strcat(home, pwd->pw_dir);
1033 	(void) strcpy(user, euser);
1034 	(void) strcat(user, pwd->pw_name);
1035 
1036 	/*
1037 	 * Need to simulate the user enviroment, minimaly set HOME, and USER.
1038 	 */
1039 	if ((child = fork1()) == 0) {
1040 		(void) putenv(home);
1041 		(void) putenv(user);
1042 		(void) setgid(pwd->pw_gid);
1043 		(void) setuid(pwd->pw_uid);
1044 
1045 		/*
1046 		 * check for shutdown flag and set environment
1047 		 */
1048 		for (ca = cmd_argv; *ca; ca++) {
1049 			if (strcmp("-h", *ca) == 0) {
1050 				(void) putenv("SYSSUSPENDDODEFAULT=");
1051 				break;
1052 			}
1053 		}
1054 
1055 		(void) execv(cmd_argv[0], cmd_argv);
1056 		exit(EXIT_FAILURE);
1057 	} else {
1058 		free(home);
1059 		free(user);
1060 		if (child == -1) {
1061 			(void) mutex_unlock(&poweroff_mutex);
1062 			return (1);
1063 		}
1064 	}
1065 	pid = 0;
1066 	while (pid != child)
1067 		pid = wait(&status);
1068 	if (WEXITSTATUS(status)) {
1069 		(void) syslog(LOG_ERR, "Failed to exec \"%s\".", cmd_argv[0]);
1070 		(void) mutex_unlock(&poweroff_mutex);
1071 		return (1);
1072 	}
1073 
1074 	(void) mutex_unlock(&poweroff_mutex);
1075 	return (0);
1076 }
1077 
1078 #define	PBUFSIZE	256
1079 
1080 /*
1081  * Gets the value of a prom property at either root or options node.  It
1082  * returns 1 if it is successful, otherwise it returns 0 .
1083  */
1084 static int
1085 get_prom(int prom_fd, prom_node_t node_name,
1086 	char *property_name, char *property_value, size_t len)
1087 {
1088 	union {
1089 		char buf[PBUFSIZE + sizeof (uint_t)];
1090 		struct openpromio opp;
1091 	} oppbuf;
1092 	register struct openpromio *opp = &(oppbuf.opp);
1093 	int	got_it = 0;
1094 
1095 	if (prom_fd == -1) {
1096 		return (0);
1097 	}
1098 
1099 	switch (node_name) {
1100 	case root:
1101 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
1102 		opp->oprom_size = PBUFSIZE;
1103 		if (ioctl(prom_fd, OPROMNEXT, opp) < 0) {
1104 			return (0);
1105 		}
1106 
1107 		/*
1108 		 * Passing null string will give us the first property.
1109 		 */
1110 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
1111 		do {
1112 			opp->oprom_size = PBUFSIZE;
1113 			if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) {
1114 				return (0);
1115 			}
1116 			if (strcmp(opp->oprom_array, property_name) == 0) {
1117 				got_it++;
1118 				break;
1119 			}
1120 		} while (opp->oprom_size > 0);
1121 
1122 		if (!got_it) {
1123 			return (0);
1124 		}
1125 		if (got_it && property_value == NULL) {
1126 			return (1);
1127 		}
1128 		opp->oprom_size = PBUFSIZE;
1129 		if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) {
1130 			return (0);
1131 		}
1132 		if (opp->oprom_size == 0) {
1133 			*property_value = '\0';
1134 		} else {
1135 			estrcpy(property_value, opp->oprom_array, len);
1136 		}
1137 		break;
1138 	case options:
1139 		estrcpy(opp->oprom_array, property_name, PBUFSIZE);
1140 		opp->oprom_size = PBUFSIZE;
1141 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
1142 			return (0);
1143 		}
1144 		if (opp->oprom_size == 0) {
1145 			return (0);
1146 		}
1147 		if (property_value != NULL) {
1148 			estrcpy(property_value, opp->oprom_array, len);
1149 		}
1150 		break;
1151 	default:
1152 		logerror("Only root node and options node are supported.\n");
1153 		return (0);
1154 	}
1155 
1156 	return (1);
1157 }
1158 
1159 #define	isspace(ch)	((ch) == ' ' || (ch) == '\t')
1160 #define	iseol(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
1161 
1162 /*ARGSUSED*/
1163 static void
1164 power_button_monitor(void *arg)
1165 {
1166 	struct pollfd pfd;
1167 	int events, ret;
1168 
1169 	if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) {
1170 		logerror("Failed to monitor the power button.");
1171 		thr_exit((void *) 0);
1172 	}
1173 
1174 	pfd.fd = pb_fd;
1175 	pfd.events = POLLIN;
1176 
1177 	/*CONSTCOND*/
1178 	while (1) {
1179 		if (poll(&pfd, 1, INFTIM) == -1) {
1180 			logerror("Failed to poll for power button events.");
1181 			thr_exit((void *) 0);
1182 		}
1183 
1184 		if (!(pfd.revents & POLLIN))
1185 			continue;
1186 
1187 		/*
1188 		 * Monitor the power button, but only take action if
1189 		 * gnome-power-manager is not running.
1190 		 *
1191 		 * ret greater than 0 means could not find process.
1192 		 */
1193 		ret = system("/usr/bin/pgrep -fx gnome-power-manager");
1194 
1195 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
1196 			logerror("Failed to get power button events.");
1197 			thr_exit((void *) 0);
1198 		}
1199 
1200 		if ((ret > 0) && (events & PB_BUTTON_PRESS) &&
1201 		    (poweroff(NULL, power_button_cmd) != 0)) {
1202 			logerror("Power button is pressed, powering "
1203 			    "down the system!");
1204 
1205 			/*
1206 			 * Send SIGPWR signal to the init process to
1207 			 * shut down the system.
1208 			 */
1209 			if (kill(1, SIGPWR) == -1)
1210 				(void) uadmin(A_SHUTDOWN, AD_POWEROFF, 0);
1211 		}
1212 
1213 		/*
1214 		 * Clear any power button event that has happened
1215 		 * meanwhile we were busy processing the last one.
1216 		 */
1217 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
1218 			logerror("Failed to get power button events.");
1219 			thr_exit((void *) 0);
1220 		}
1221 	}
1222 }
1223 
1224 static void
1225 do_attach(void)
1226 {
1227 	if (read_cpr_config() < 0)
1228 		return;
1229 
1230 	/*
1231 	 * If autopm behavior is explicitly enabled for energystar-v2, or
1232 	 * set to default for energystar-v3, create a new thread to attach
1233 	 * all devices.
1234 	 */
1235 	estar_v3_prop = asinfo.is_autopm_default;
1236 	if ((strcmp(asinfo.apm_behavior, "enable") == 0) ||
1237 	    (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) {
1238 		if (powerd_debug)
1239 			logerror("powerd starting device attach thread.");
1240 		if (thr_create(NULL, NULL, attach_devices, NULL,
1241 		    THR_DAEMON, NULL) != 0) {
1242 			logerror("Unable to create thread to attach devices.");
1243 		}
1244 	}
1245 }
1246 
1247 /*ARGSUSED*/
1248 static void *
1249 attach_devices(void *arg)
1250 {
1251 	di_node_t root_node;
1252 
1253 	(void) sleep(60);	/* let booting finish first */
1254 
1255 	if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) {
1256 		logerror("Failed to attach devices.");
1257 		return (NULL);
1258 	}
1259 	di_fini(root_node);
1260 
1261 	/*
1262 	 * Unload all the modules.
1263 	 */
1264 	(void) modctl(MODUNLOAD, 0);
1265 
1266 	return (NULL);
1267 }
1268 
1269 
1270 /*
1271  * Create a file which will contain our pid.  Pmconfig will check this file
1272  * to see if we are running and can use the pid to signal us.  Returns the
1273  * file descriptor if successful, -1 otherwise.
1274  *
1275  * Note: Deal with attempt to launch multiple instances and also with existence
1276  * of an obsolete pid file caused by an earlier abort.
1277  */
1278 static int
1279 open_pidfile(char *me)
1280 {
1281 	int fd;
1282 	const char *e1 = "%s: Cannot open pid file for read: ";
1283 	const char *e2 = "%s: Cannot unlink obsolete pid file: ";
1284 	const char *e3 = "%s: Either another daemon is running or the"
1285 	    " process is defunct (pid %d). \n";
1286 	const char *e4 = "%s: Cannot create pid file: ";
1287 
1288 again:
1289 	if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) {
1290 		if (errno  == EEXIST) {
1291 			FILE *fp;
1292 			pid_t pid;
1293 
1294 			if ((fp = fopen(pidpath, "r")) == NULL) {
1295 				(void) fprintf(stderr, e1, me);
1296 				perror(NULL);
1297 				return (-1);
1298 			}
1299 
1300 			/* Read the pid */
1301 			pid = (pid_t)-1;
1302 			(void) fscanf(fp, "%ld", &pid);
1303 			(void) fclose(fp);
1304 			if (pid == -1) {
1305 				if (unlink(pidpath) == -1) {
1306 					(void) fprintf(stderr, e2, me);
1307 					perror(NULL);
1308 					return (-1);
1309 				} else /* try without corrupted file */
1310 					goto again;
1311 			}
1312 
1313 			/* Is pid for a running process */
1314 			if (kill(pid, 0) == -1) {
1315 				if (errno == ESRCH) {
1316 					if (unlink(pidpath) == -1) {
1317 						(void) fprintf(stderr, e2, me);
1318 						perror(NULL);
1319 						return (-1);
1320 					} else	/* try without obsolete file */
1321 						goto again;
1322 				}
1323 			} else {    /* powerd deamon still running or defunct */
1324 				(void) fprintf(stderr, e3, me, pid);
1325 				return (-1);
1326 			}
1327 
1328 		} else {	/* create failure not due to existing file */
1329 			(void) fprintf(stderr, e4, me);
1330 			perror(NULL);
1331 			return (-1);
1332 		}
1333 	}
1334 
1335 	(void) fchown(fd, (uid_t)-1, (gid_t)0);
1336 	return (fd);
1337 }
1338 
1339 /*
1340  * Write a pid to the pid file.  Report errors to syslog.
1341  *
1342  */
1343 static int
1344 write_pidfile(int fd, pid_t pid)
1345 {
1346 	int	len;
1347 	int	rc = 0;			/* assume success */
1348 
1349 	len = sprintf(scratch, "%ld\n", pid);
1350 	if (write(fd, scratch, len) != len) {
1351 		logerror("Cannot write pid file: %s", strerror(errno));
1352 		rc = -1;
1353 	}
1354 
1355 	return (rc);
1356 }
1357