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