xref: /onnv-gate/usr/src/cmd/power/powerd.c (revision 3028:ecc075a2fc74)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3028Smh27603  * Common Development and Distribution License (the "License").
6*3028Smh27603  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3028Smh27603  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <stdio.h>			/* Standard */
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <fcntl.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <time.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <errno.h>
340Sstevel@tonic-gate #include <pwd.h>
350Sstevel@tonic-gate #include <procfs.h>
360Sstevel@tonic-gate #include <dirent.h>
370Sstevel@tonic-gate #include <thread.h>
380Sstevel@tonic-gate #include <limits.h>
390Sstevel@tonic-gate #include <sys/todio.h>			/* Time-Of-Day chip */
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <sys/wait.h>
420Sstevel@tonic-gate #include <sys/ipc.h>			/* IPC functions */
430Sstevel@tonic-gate #include <signal.h>			/* signal handling */
440Sstevel@tonic-gate #include <syslog.h>
450Sstevel@tonic-gate #include <unistd.h>
460Sstevel@tonic-gate #include <libdevinfo.h>
470Sstevel@tonic-gate #include <poll.h>
480Sstevel@tonic-gate #include <sys/pm.h>			/* power management driver */
490Sstevel@tonic-gate #include <sys/uadmin.h>
500Sstevel@tonic-gate #include <sys/openpromio.h>		/* for prom access */
510Sstevel@tonic-gate #include <sys/sysmacros.h>		/* for MIN & MAX macros */
520Sstevel@tonic-gate #include <sys/modctl.h>
530Sstevel@tonic-gate #include <sys/stropts.h>		/* for INFTIM */
540Sstevel@tonic-gate #include <sys/pbio.h>
550Sstevel@tonic-gate #include <sys/cpr.h>
560Sstevel@tonic-gate #include <stdarg.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include "powerd.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /* External Functions */
610Sstevel@tonic-gate extern struct tm *localtime_r(const time_t *, struct tm *);
620Sstevel@tonic-gate extern void sysstat_init(void);
630Sstevel@tonic-gate extern int check_tty(hrtime_t *, int);
640Sstevel@tonic-gate extern int check_disks(hrtime_t *, int);
650Sstevel@tonic-gate extern int check_load_ave(hrtime_t *, float);
660Sstevel@tonic-gate extern int check_nfs(hrtime_t *, int);
670Sstevel@tonic-gate extern int last_disk_activity(hrtime_t *, int);
680Sstevel@tonic-gate extern int last_tty_activity(hrtime_t *, int);
690Sstevel@tonic-gate extern int last_load_ave_activity(hrtime_t *);
700Sstevel@tonic-gate extern int last_nfs_activity(hrtime_t *, int);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #define	PM		"/dev/pm"
730Sstevel@tonic-gate #define	TOD		"/dev/tod"
740Sstevel@tonic-gate #define	PROM		"/dev/openprom"
750Sstevel@tonic-gate #define	PB		"/dev/power_button"
760Sstevel@tonic-gate #define	LOGFILE		"./powerd.log"
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	PBM_THREAD	0
790Sstevel@tonic-gate #define	ATTACH_THREAD	1
800Sstevel@tonic-gate #define	NUM_THREADS	2
810Sstevel@tonic-gate 
820Sstevel@tonic-gate #define	CHECK_INTERVAL	5
830Sstevel@tonic-gate #define	IDLECHK_INTERVAL	15
840Sstevel@tonic-gate #define	MINS_TO_SECS	60
850Sstevel@tonic-gate #define	HOURS_TO_SECS	(60 * 60)
860Sstevel@tonic-gate #define	DAYS_TO_SECS	(24 * 60 * 60)
870Sstevel@tonic-gate #define	HOURS_TO_MINS	60
880Sstevel@tonic-gate #define	DAYS_TO_MINS	(24 * 60)
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #define	LIFETIME_SECS			(7 * 365 * DAYS_TO_SECS)
910Sstevel@tonic-gate #define	DEFAULT_POWER_CYCLE_LIMIT	10000
920Sstevel@tonic-gate #define	DEFAULT_SYSTEM_BOARD_DATE	804582000	/* July 1, 1995 */
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #define	LLEN 80
950Sstevel@tonic-gate 
960Sstevel@tonic-gate typedef	enum {root, options} prom_node_t;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /* State Variables */
990Sstevel@tonic-gate static struct cprconfig	asinfo;
1000Sstevel@tonic-gate static time_t		shutdown_time;	/* Time for next shutdown check */
1010Sstevel@tonic-gate static time_t		checkidle_time;	/* Time for next idleness check */
1020Sstevel@tonic-gate static time_t		last_resume;
1030Sstevel@tonic-gate pwr_info_t		*info;		/* private as config data buffer */
1040Sstevel@tonic-gate static int		pb_fd;		/* power button driver */
1050Sstevel@tonic-gate static int		broadcast;	/* Enables syslog messages */
1060Sstevel@tonic-gate static int		start_calc;
1070Sstevel@tonic-gate static int		autoshutdown_en;
1080Sstevel@tonic-gate static int		do_idlecheck;
1090Sstevel@tonic-gate static int		got_sighup;
1100Sstevel@tonic-gate static int		estar_v2_prop;
111*3028Smh27603 #ifdef sparc
1120Sstevel@tonic-gate static int		estar_v3_prop;
113*3028Smh27603 #endif
1140Sstevel@tonic-gate static int		log_power_cycles_error = 0;
1150Sstevel@tonic-gate static int		log_system_board_date_error = 0;
1160Sstevel@tonic-gate static int		log_no_autoshutdown_warning = 0;
1170Sstevel@tonic-gate static mutex_t		poweroff_mutex;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static char *autoshutdown_cmd[] = {
1200Sstevel@tonic-gate 	"/usr/openwin/bin/sys-suspend",
1210Sstevel@tonic-gate 	"-n", "-d", ":0", NULL
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static char *power_button_cmd[] = {
1250Sstevel@tonic-gate 	"/usr/openwin/bin/sys-suspend",
1260Sstevel@tonic-gate 	"-h", "-d", ":0", NULL
1270Sstevel@tonic-gate };
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static char pidpath[] = PIDPATH;
1300Sstevel@tonic-gate static char scratch[PATH_MAX];
1310Sstevel@tonic-gate static char *prog;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /* Local Functions */
1340Sstevel@tonic-gate static void alarm_handler(int);
1350Sstevel@tonic-gate static void thaw_handler(int);
1360Sstevel@tonic-gate static void kill_handler(int);
1370Sstevel@tonic-gate static void work_handler(int);
1380Sstevel@tonic-gate static void check_shutdown(time_t *, hrtime_t *);
1390Sstevel@tonic-gate static void check_idleness(time_t *, hrtime_t *);
1400Sstevel@tonic-gate static int last_system_activity(hrtime_t *);
1410Sstevel@tonic-gate static int run_idlecheck(void);
1420Sstevel@tonic-gate static void set_alarm(time_t);
143*3028Smh27603 static int poweroff(const char *, char **);
1440Sstevel@tonic-gate static int is_ok2shutdown(time_t *);
1450Sstevel@tonic-gate static int get_prom(int, prom_node_t, char *, char *, size_t);
1460Sstevel@tonic-gate static void power_button_monitor(void *);
1470Sstevel@tonic-gate static int open_pidfile(char *);
1480Sstevel@tonic-gate static int write_pidfile(int, pid_t);
1490Sstevel@tonic-gate static int read_cpr_config(void);
1500Sstevel@tonic-gate static void system_activity_monitor(void);
1510Sstevel@tonic-gate #ifdef sparc
1520Sstevel@tonic-gate static void do_attach(void);
1530Sstevel@tonic-gate static void *attach_devices(void *);
1540Sstevel@tonic-gate #endif
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 
157*3028Smh27603 /* PRINTFLIKE1 */
1580Sstevel@tonic-gate static void
159*3028Smh27603 logerror(const char *fmt, ...)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	va_list args;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	va_start(args, fmt);
1640Sstevel@tonic-gate 	if (broadcast)
1650Sstevel@tonic-gate 		vsyslog(LOG_ERR, fmt, args);
1660Sstevel@tonic-gate 	va_end(args);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate static void
1710Sstevel@tonic-gate estrcpy(char *dst, char *src, size_t dlen)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	size_t slen;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	slen = strlcpy(dst, src, dlen);
1760Sstevel@tonic-gate 	if (slen >= dlen) {
1770Sstevel@tonic-gate 		logerror("%s: string too long \"%s ...\"\n"
1780Sstevel@tonic-gate 		    "(len %d, max %d)\n", prog, dst, slen, dlen - 1);
1790Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate int
1850Sstevel@tonic-gate main(int argc, char *argv[])
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	pid_t		pid;
1880Sstevel@tonic-gate 	int		pm_fd;
1890Sstevel@tonic-gate 	struct sigaction act;
1900Sstevel@tonic-gate 	sigset_t	sigmask;
1910Sstevel@tonic-gate 	int		c;
1920Sstevel@tonic-gate 	char		errmsg[PATH_MAX + 64];
1930Sstevel@tonic-gate 	int		pid_fd;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	prog = argv[0];
1960Sstevel@tonic-gate 	if (geteuid() != 0) {
1970Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: Must be root\n", prog);
1980Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if ((pid_fd = open_pidfile(prog)) ==  -1)
2020Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * Process options
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	broadcast = 1;
2080Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "n")) != EOF) {
2090Sstevel@tonic-gate 		switch (c) {
2100Sstevel@tonic-gate 		case 'n':
2110Sstevel@tonic-gate 			broadcast = 0;
2120Sstevel@tonic-gate 			break;
2130Sstevel@tonic-gate 		case '?':
2140Sstevel@tonic-gate 			(void) fprintf(stderr, "Usage: %s [-n]\n", prog);
2150Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	pm_fd = open(PM, O_RDWR);
2200Sstevel@tonic-gate 	if (pm_fd == -1) {
221*3028Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM);
2220Sstevel@tonic-gate 		perror(errmsg);
2230Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	(void) close(pm_fd);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/*
2280Sstevel@tonic-gate 	 * Initialize mutex lock used to insure only one command to
2290Sstevel@tonic-gate 	 * run at a time.
2300Sstevel@tonic-gate 	 */
2310Sstevel@tonic-gate 	if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) {
2320Sstevel@tonic-gate 		(void) fprintf(stderr,
2330Sstevel@tonic-gate 			"%s: Unable to initialize mutex lock\n", prog);
2340Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) {
238*3028Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog);
2390Sstevel@tonic-gate 		perror(errmsg);
2400Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/*
2440Sstevel@tonic-gate 	 * Daemon is set to go...
2450Sstevel@tonic-gate 	 */
2460Sstevel@tonic-gate 	if ((pid = fork()) < 0)
2470Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2480Sstevel@tonic-gate 	else if (pid != 0)
2490Sstevel@tonic-gate 		exit(EXIT_SUCCESS);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	pid = getpid();
2520Sstevel@tonic-gate 	openlog(prog, 0, LOG_DAEMON);
2530Sstevel@tonic-gate 	if (write_pidfile(pid_fd, pid) == -1)	/* logs errors on failure */
2540Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2550Sstevel@tonic-gate 	(void) close(pid_fd);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * Close all the parent's file descriptors (Bug 1225843).
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	closefrom(0);
2610Sstevel@tonic-gate 	(void) setsid();
2620Sstevel@tonic-gate 	(void) chdir("/");
2630Sstevel@tonic-gate 	(void) umask(0);
2640Sstevel@tonic-gate #ifdef DEBUG
2650Sstevel@tonic-gate 	/*
2660Sstevel@tonic-gate 	 * Connect stdout to the console.
2670Sstevel@tonic-gate 	 */
2680Sstevel@tonic-gate 	if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) {
2690Sstevel@tonic-gate 		logerror("Unable to connect to the console.");
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate #endif
2720Sstevel@tonic-gate 	info->pd_flags = PD_AC;
2730Sstevel@tonic-gate 	info->pd_idle_time = -1;
2740Sstevel@tonic-gate 	info->pd_start_time = 0;
2750Sstevel@tonic-gate 	info->pd_finish_time = 0;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/*
2780Sstevel@tonic-gate 	 * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
2790Sstevel@tonic-gate 	 * any time
2800Sstevel@tonic-gate 	 */
2810Sstevel@tonic-gate 	act.sa_handler = kill_handler;
2820Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
2830Sstevel@tonic-gate 	act.sa_flags = 0;
2840Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &act, NULL);
2850Sstevel@tonic-gate 	(void) sigaction(SIGINT, &act, NULL);
2860Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &act, NULL);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	(void) sigfillset(&sigmask);
2890Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGQUIT);
2900Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGINT);
2910Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTERM);
2920Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * If "power_button" device node can be opened, create a new
2960Sstevel@tonic-gate 	 * thread to monitor the power button.
2970Sstevel@tonic-gate 	 */
2980Sstevel@tonic-gate 	if ((pb_fd = open(PB, O_RDONLY)) != -1) {
2990Sstevel@tonic-gate 		if (thr_create(NULL, NULL,
3000Sstevel@tonic-gate 		    (void *(*)(void *))power_button_monitor, NULL,
3010Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
3020Sstevel@tonic-gate 			logerror("Unable to monitor system's power button.");
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate #ifdef sparc
3070Sstevel@tonic-gate 	do_attach();
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/*
3110Sstevel@tonic-gate 	 * Create a new thread to monitor system activity and suspend
3120Sstevel@tonic-gate 	 * system if idle.
3130Sstevel@tonic-gate 	 */
3140Sstevel@tonic-gate 	if (thr_create(NULL, NULL,
3150Sstevel@tonic-gate 	    (void *(*)(void *))system_activity_monitor, NULL,
3160Sstevel@tonic-gate 	    THR_DAEMON, NULL) != 0) {
3170Sstevel@tonic-gate 		logerror("Unable to create thread to monitor system activity.");
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * Block until we receive an explicit terminate signal
3220Sstevel@tonic-gate 	 */
3230Sstevel@tonic-gate 	(void) sigsuspend(&sigmask);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	return (1);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate static void
3290Sstevel@tonic-gate system_activity_monitor(void)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate 	struct sigaction act;
3320Sstevel@tonic-gate 	sigset_t sigmask;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * Setup for gathering system's statistic.
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	sysstat_init();
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/*
3400Sstevel@tonic-gate 	 * In addition to the SIGQUIT, SIGINT and SIGTERM signals already
3410Sstevel@tonic-gate 	 * being handled, this thread also needs to handle SIGHUP, SIGALRM
3420Sstevel@tonic-gate 	 * and SIGTHAW signals.
3430Sstevel@tonic-gate 	 */
3440Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
3450Sstevel@tonic-gate 	act.sa_flags = 0;
3460Sstevel@tonic-gate 	act.sa_handler = alarm_handler;
3470Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &act, NULL);
3480Sstevel@tonic-gate 	act.sa_handler = work_handler;
3490Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &act, NULL);
3500Sstevel@tonic-gate 	act.sa_handler = thaw_handler;
3510Sstevel@tonic-gate 	(void) sigaction(SIGTHAW, &act, NULL);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * Invoke work_handler with a dummy SIGHUP signal to read
3550Sstevel@tonic-gate 	 * cpr config file, get autoshutdown properties and schedule
3560Sstevel@tonic-gate 	 * an alarm if needed.
3570Sstevel@tonic-gate 	 */
3580Sstevel@tonic-gate 	work_handler(SIGHUP);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * Wait for signal to read file
3620Sstevel@tonic-gate 	 */
3630Sstevel@tonic-gate 	(void) thr_sigsetmask(0, 0, &sigmask);
3640Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGHUP);
3650Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGALRM);
3660Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTHAW);
3670Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
3680Sstevel@tonic-gate 	do {
3690Sstevel@tonic-gate 		(void) sigsuspend(&sigmask);
3700Sstevel@tonic-gate 	} while (errno == EINTR);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate static int
3740Sstevel@tonic-gate read_cpr_config(void)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	int	asfd;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if ((asfd = open(CPR_CONFIG, O_RDONLY)) < 0) {
3790Sstevel@tonic-gate 		logerror("Unable to open CPR config file '%s'", CPR_CONFIG);
3800Sstevel@tonic-gate 		return (-1);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if (read(asfd, (void *)&asinfo, sizeof (asinfo)) != sizeof (asinfo)) {
3840Sstevel@tonic-gate 		logerror("Unable to read CPR config file '%s'", CPR_CONFIG);
3850Sstevel@tonic-gate 		close(asfd);
3860Sstevel@tonic-gate 		return (-1);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	(void) close(asfd);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	return (0);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate /*ARGSUSED*/
3950Sstevel@tonic-gate static void
3960Sstevel@tonic-gate thaw_handler(int sig)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	start_calc  = 0;
3990Sstevel@tonic-gate 	last_resume = time(NULL);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate /*ARGSUSED*/
4030Sstevel@tonic-gate static void
4040Sstevel@tonic-gate kill_handler(int sig)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate 	int ret_code = EXIT_SUCCESS;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/*
4090Sstevel@tonic-gate 	 * Free resources
4100Sstevel@tonic-gate 	 */
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	free(info);
4130Sstevel@tonic-gate 	if (pb_fd != -1) {
4140Sstevel@tonic-gate 		(void) close(pb_fd);
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 	(void) mutex_destroy(&poweroff_mutex);
4170Sstevel@tonic-gate 	(void) unlink(pidpath);
4180Sstevel@tonic-gate 	closelog();
4190Sstevel@tonic-gate 	exit(ret_code);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*ARGSUSED*/
4230Sstevel@tonic-gate static void
4240Sstevel@tonic-gate alarm_handler(int sig)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	time_t		now;
4270Sstevel@tonic-gate 	hrtime_t	hr_now;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	now = time(NULL);
4300Sstevel@tonic-gate 	hr_now = gethrtime();
4310Sstevel@tonic-gate 	if (checkidle_time <= now && checkidle_time != 0)
4320Sstevel@tonic-gate 		check_idleness(&now, &hr_now);
4330Sstevel@tonic-gate 	if (shutdown_time <= now && shutdown_time != 0)
4340Sstevel@tonic-gate 		check_shutdown(&now, &hr_now);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	set_alarm(now);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate /*ARGSUSED*/
4400Sstevel@tonic-gate static void
4410Sstevel@tonic-gate work_handler(int sig)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	time_t		now;
4440Sstevel@tonic-gate 	hrtime_t	hr_now;
4450Sstevel@tonic-gate 	struct stat	stat_buf;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	do_idlecheck = 0;
4480Sstevel@tonic-gate 	info->pd_flags = PD_AC;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/*
4510Sstevel@tonic-gate 	 * Parse the config file for autoshutdown and idleness entries.
4520Sstevel@tonic-gate 	 */
4530Sstevel@tonic-gate 	if (read_cpr_config() < 0)
4540Sstevel@tonic-gate 		return;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/*
4570Sstevel@tonic-gate 	 * Since Oct. 1, 1995, any new system shipped had root
4580Sstevel@tonic-gate 	 * property "energystar-v2" defined in its prom.  Systems
4590Sstevel@tonic-gate 	 * shipped after July 1, 1999, will have "energystar-v3"
4600Sstevel@tonic-gate 	 * property.
4610Sstevel@tonic-gate 	 */
4620Sstevel@tonic-gate 	estar_v2_prop = asinfo.is_cpr_default;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	info->pd_flags |= asinfo.is_autowakeup_capable;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if (strlen(asinfo.idlecheck_path) > 0) {
4670Sstevel@tonic-gate 		if (stat(asinfo.idlecheck_path, &stat_buf) != 0) {
4680Sstevel@tonic-gate 			logerror("unable to access idlecheck program \"%s\".",
4690Sstevel@tonic-gate 			    asinfo.idlecheck_path);
4700Sstevel@tonic-gate 		} else if (!(stat_buf.st_mode & S_IXUSR)) {
4710Sstevel@tonic-gate 			logerror("idlecheck program \"%s\" is not executable.",
4720Sstevel@tonic-gate 			    asinfo.idlecheck_path);
4730Sstevel@tonic-gate 		} else {
4740Sstevel@tonic-gate 			do_idlecheck = 1;
4750Sstevel@tonic-gate 		}
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (strlen(asinfo.as_behavior) == 0 ||
4790Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "noshutdown") == 0 ||
4800Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "unconfigured") == 0) {
4810Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
4820Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "default") == 0) {
4830Sstevel@tonic-gate 		info->pd_autoshutdown = estar_v2_prop;
4840Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "shutdown") == 0 ||
4850Sstevel@tonic-gate 		strcmp(asinfo.as_behavior, "autowakeup") == 0) {
4860Sstevel@tonic-gate 		info->pd_autoshutdown = asinfo.is_cpr_capable;
4870Sstevel@tonic-gate 	} else {
4880Sstevel@tonic-gate 		logerror("autoshutdown behavior \"%s\" unrecognized.",
4890Sstevel@tonic-gate 		    asinfo.as_behavior);
4900Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (info->pd_autoshutdown) {
4940Sstevel@tonic-gate 		info->pd_idle_time = asinfo.as_idle;
4950Sstevel@tonic-gate 		info->pd_start_time =
4960Sstevel@tonic-gate 		    (asinfo.as_sh * 60 + asinfo.as_sm) % DAYS_TO_MINS;
4970Sstevel@tonic-gate 		info->pd_finish_time =
4980Sstevel@tonic-gate 		    (asinfo.as_fh * 60 + asinfo.as_fm) % DAYS_TO_MINS;
4990Sstevel@tonic-gate 		info->pd_autoresume =
5000Sstevel@tonic-gate 		    (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0;
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown)
5030Sstevel@tonic-gate 		? 1 : 0;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate #ifdef DEBUG
5060Sstevel@tonic-gate 	(void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, "
5070Sstevel@tonic-gate 			"pd_autoresume = %d\n",
5080Sstevel@tonic-gate 		autoshutdown_en, asinfo.as_idle, info->pd_autoresume);
5090Sstevel@tonic-gate 	(void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n",
5100Sstevel@tonic-gate 		info->pd_start_time, info->pd_finish_time);
5110Sstevel@tonic-gate #endif
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	got_sighup = 1;
5140Sstevel@tonic-gate 	now = last_resume = time(NULL);
5150Sstevel@tonic-gate 	hr_now = gethrtime();
5160Sstevel@tonic-gate 	check_idleness(&now, &hr_now);
5170Sstevel@tonic-gate 	check_shutdown(&now, &hr_now);
5180Sstevel@tonic-gate 	set_alarm(now);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate static void
5220Sstevel@tonic-gate check_shutdown(time_t *now, hrtime_t *hr_now)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	int		tod_fd = -1;
5250Sstevel@tonic-gate 	int		kbd, mouse, system, least_idle, idlecheck_time;
5260Sstevel@tonic-gate 	int		next_time;
5270Sstevel@tonic-gate 	int		s, f;
5280Sstevel@tonic-gate 	struct tm	tmp_time;
5290Sstevel@tonic-gate 	time_t		start_of_day, time_since_last_resume;
5300Sstevel@tonic-gate 	time_t		wakeup_time;
5310Sstevel@tonic-gate 	extern long	conskbd_idle_time(void);
5320Sstevel@tonic-gate 	extern long	consms_idle_time(void);
5330Sstevel@tonic-gate 	static int	warned_kbd, warned_ms; /* print error msg one time */
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (!autoshutdown_en) {
5360Sstevel@tonic-gate 		shutdown_time = 0;
5370Sstevel@tonic-gate 		return;
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	(void) localtime_r(now, &tmp_time);
5410Sstevel@tonic-gate 	tmp_time.tm_sec = 0;
5420Sstevel@tonic-gate 	tmp_time.tm_min = 0;
5430Sstevel@tonic-gate 	tmp_time.tm_hour = 0;
5440Sstevel@tonic-gate 	start_of_day = mktime(&tmp_time);
5450Sstevel@tonic-gate 	s = start_of_day + info->pd_start_time * 60;
5460Sstevel@tonic-gate 	f = start_of_day + info->pd_finish_time * 60;
5470Sstevel@tonic-gate 	if ((s < f && *now >= s && *now < f) ||
5480Sstevel@tonic-gate 	    (s >= f && (*now < f || *now >= s))) {
5490Sstevel@tonic-gate 		if ((mouse = (int)consms_idle_time()) < 0) {
5500Sstevel@tonic-gate 			if (! warned_ms) {
5510Sstevel@tonic-gate 				warned_ms = 1;
5520Sstevel@tonic-gate 				logerror("powerd: failed to get "
5530Sstevel@tonic-gate 				    "idle time for console mouse");
5540Sstevel@tonic-gate 			}
5550Sstevel@tonic-gate 			return;
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 		if ((kbd = (int)conskbd_idle_time()) < 0) {
5580Sstevel@tonic-gate 			if (! warned_kbd) {
5590Sstevel@tonic-gate 				warned_kbd = 1;
5600Sstevel@tonic-gate 				logerror("powerd: failed to get "
5610Sstevel@tonic-gate 				    "idle time for console keyboard");
5620Sstevel@tonic-gate 			}
5630Sstevel@tonic-gate 			return;
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		system = last_system_activity(hr_now);
5670Sstevel@tonic-gate 		/* who is the last to go idle */
5680Sstevel@tonic-gate 		least_idle = MIN(system, MIN(kbd, mouse));
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 		/*
5710Sstevel@tonic-gate 		 * Calculate time_since_last_resume and the next_time
5720Sstevel@tonic-gate 		 * to auto suspend.
5730Sstevel@tonic-gate 		 */
5740Sstevel@tonic-gate 		start_calc = 1;
5750Sstevel@tonic-gate 		time_since_last_resume = time(NULL) - last_resume;
5760Sstevel@tonic-gate 		next_time = info->pd_idle_time * 60 -
5770Sstevel@tonic-gate 				MIN(least_idle, time_since_last_resume);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate #ifdef DEBUG
5800Sstevel@tonic-gate 		fprintf(stderr, " check_shutdown: next_time=%d\n",
5810Sstevel@tonic-gate 			next_time);
5820Sstevel@tonic-gate #endif
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		/*
5850Sstevel@tonic-gate 		 * If we have get the SIGTHAW signal at this point - our
5860Sstevel@tonic-gate 		 * calculation of time_since_last_resume is wrong  so
5870Sstevel@tonic-gate 		 * - we need to recalculate.
5880Sstevel@tonic-gate 		 */
5890Sstevel@tonic-gate 		while (start_calc == 0) {
5900Sstevel@tonic-gate 			/* need to redo calculation */
5910Sstevel@tonic-gate 			start_calc = 1;
5920Sstevel@tonic-gate 			time_since_last_resume = time(NULL) - last_resume;
5930Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
5940Sstevel@tonic-gate 				MIN(least_idle, time_since_last_resume);
5950Sstevel@tonic-gate 		}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		/*
5980Sstevel@tonic-gate 		 * Only when everything else is idle, run the user's idlecheck
5990Sstevel@tonic-gate 		 * script.
6000Sstevel@tonic-gate 		 */
6010Sstevel@tonic-gate 		if (next_time <= 0 && do_idlecheck) {
6020Sstevel@tonic-gate 			got_sighup = 0;
6030Sstevel@tonic-gate 			idlecheck_time = run_idlecheck();
6040Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
6050Sstevel@tonic-gate 				MIN(idlecheck_time, MIN(least_idle,
6060Sstevel@tonic-gate 				time_since_last_resume));
6070Sstevel@tonic-gate 			/*
6080Sstevel@tonic-gate 			 * If we have caught SIGTHAW or SIGHUP, need to
6090Sstevel@tonic-gate 			 * recalculate.
6100Sstevel@tonic-gate 			 */
6110Sstevel@tonic-gate 			while (start_calc == 0 || got_sighup == 1) {
6120Sstevel@tonic-gate 				start_calc = 1;
6130Sstevel@tonic-gate 				got_sighup = 0;
6140Sstevel@tonic-gate 				idlecheck_time = run_idlecheck();
6150Sstevel@tonic-gate 				time_since_last_resume = time(NULL) -
6160Sstevel@tonic-gate 					last_resume;
6170Sstevel@tonic-gate 				next_time = info->pd_idle_time * 60 -
6180Sstevel@tonic-gate 					MIN(idlecheck_time, MIN(least_idle,
6190Sstevel@tonic-gate 					time_since_last_resume));
6200Sstevel@tonic-gate 			}
6210Sstevel@tonic-gate 		}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		if (next_time <= 0) {
6240Sstevel@tonic-gate 			if (is_ok2shutdown(now)) {
6250Sstevel@tonic-gate 				/*
6260Sstevel@tonic-gate 				 * Setup the autowakeup alarm.  Clear it
6270Sstevel@tonic-gate 				 * right after poweroff, just in case if
6280Sstevel@tonic-gate 				 * shutdown doesn't go through.
6290Sstevel@tonic-gate 				 */
6300Sstevel@tonic-gate 				if (info->pd_autoresume)
6310Sstevel@tonic-gate 					tod_fd = open(TOD, O_RDWR);
6320Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
6330Sstevel@tonic-gate 					wakeup_time = (*now < f) ? f :
6340Sstevel@tonic-gate 							(f + DAYS_TO_SECS);
6350Sstevel@tonic-gate 					/*
6360Sstevel@tonic-gate 					 * A software fix for hardware
6370Sstevel@tonic-gate 					 * bug 1217415.
6380Sstevel@tonic-gate 					 */
6390Sstevel@tonic-gate 					if ((wakeup_time - *now) < 180) {
6400Sstevel@tonic-gate 						logerror(
6410Sstevel@tonic-gate 		"Since autowakeup time is less than 3 minutes away, "
6420Sstevel@tonic-gate 		"autoshutdown will not occur.");
6430Sstevel@tonic-gate 						shutdown_time = *now + 180;
6440Sstevel@tonic-gate 						close(tod_fd);
6450Sstevel@tonic-gate 						return;
6460Sstevel@tonic-gate 					}
6470Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_SET_ALARM,
6480Sstevel@tonic-gate 							&wakeup_time) == -1) {
6490Sstevel@tonic-gate 						logerror("Unable to program "
6500Sstevel@tonic-gate 							"TOD alarm for "
6510Sstevel@tonic-gate 							"autowakeup.");
6520Sstevel@tonic-gate 						close(tod_fd);
6530Sstevel@tonic-gate 						return;
6540Sstevel@tonic-gate 					}
6550Sstevel@tonic-gate 				}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 				(void) poweroff("Autoshutdown",
6580Sstevel@tonic-gate 				    autoshutdown_cmd);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
6610Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_CLEAR_ALARM,
6620Sstevel@tonic-gate 							NULL) == -1)
6630Sstevel@tonic-gate 						logerror("Unable to clear "
6640Sstevel@tonic-gate 						    "alarm in TOD device.");
6650Sstevel@tonic-gate 					close(tod_fd);
6660Sstevel@tonic-gate 				}
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 				(void) time(now);
6690Sstevel@tonic-gate 				/* wait at least 5 mins */
6700Sstevel@tonic-gate 				shutdown_time = *now +
6710Sstevel@tonic-gate 					((info->pd_idle_time * 60) > 300 ?
6720Sstevel@tonic-gate 					(info->pd_idle_time * 60) : 300);
6730Sstevel@tonic-gate 			} else {
6740Sstevel@tonic-gate 				/* wait 5 mins */
6750Sstevel@tonic-gate 				shutdown_time = *now + 300;
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 		} else
6780Sstevel@tonic-gate 			shutdown_time = *now + next_time;
6790Sstevel@tonic-gate 	} else if (s < f && *now >= f) {
6800Sstevel@tonic-gate 		shutdown_time = s + DAYS_TO_SECS;
6810Sstevel@tonic-gate 	} else
6820Sstevel@tonic-gate 		shutdown_time = s;
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate static int
6860Sstevel@tonic-gate is_ok2shutdown(time_t *now)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	int	prom_fd = -1;
6890Sstevel@tonic-gate 	char	power_cycles_st[LLEN];
6900Sstevel@tonic-gate 	char	power_cycle_limit_st[LLEN];
6910Sstevel@tonic-gate 	char	system_board_date_st[LLEN];
6920Sstevel@tonic-gate 	int	power_cycles, power_cycle_limit, free_cycles, scaled_cycles;
6930Sstevel@tonic-gate 	time_t	life_began, life_passed;
6940Sstevel@tonic-gate 	int	no_power_cycles = 0;
6950Sstevel@tonic-gate 	int	no_system_board_date = 0;
6960Sstevel@tonic-gate 	int	ret = 1;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/* CONSTCOND */
6990Sstevel@tonic-gate 	while (1) {
7000Sstevel@tonic-gate 		if ((prom_fd = open(PROM, O_RDWR)) == -1 &&
7010Sstevel@tonic-gate 			(errno == EAGAIN))
7020Sstevel@tonic-gate 				continue;
7030Sstevel@tonic-gate 		break;
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * when #power-cycles property does not exist
7080Sstevel@tonic-gate 	 * power cycles are unlimited.
7090Sstevel@tonic-gate 	 */
7100Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "#power-cycles",
7110Sstevel@tonic-gate 	    power_cycles_st, sizeof (power_cycles_st)) == 0)
7120Sstevel@tonic-gate 		goto ckdone;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	if (get_prom(prom_fd, root, "power-cycle-limit",
7150Sstevel@tonic-gate 	    power_cycle_limit_st, sizeof (power_cycle_limit_st)) == 0) {
7160Sstevel@tonic-gate 		power_cycle_limit = DEFAULT_POWER_CYCLE_LIMIT;
7170Sstevel@tonic-gate 	} else {
7180Sstevel@tonic-gate 		power_cycle_limit = atoi(power_cycle_limit_st);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	/*
7220Sstevel@tonic-gate 	 * Allow 10% of power_cycle_limit as free cycles.
7230Sstevel@tonic-gate 	 */
724*3028Smh27603 	free_cycles = power_cycle_limit / 10;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	power_cycles = atoi(power_cycles_st);
7270Sstevel@tonic-gate 	if (power_cycles < 0)
7280Sstevel@tonic-gate 		no_power_cycles++;
7290Sstevel@tonic-gate 	else if (power_cycles <= free_cycles)
7300Sstevel@tonic-gate 		goto ckdone;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (no_power_cycles && log_power_cycles_error == 0) {
7330Sstevel@tonic-gate 		logerror("Invalid PROM property \"#power-cycles\" was found.");
7340Sstevel@tonic-gate 		log_power_cycles_error++;
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "system-board-date",
7380Sstevel@tonic-gate 	    system_board_date_st, sizeof (system_board_date_st)) == 0) {
7390Sstevel@tonic-gate 		no_system_board_date++;
7400Sstevel@tonic-gate 	} else {
7410Sstevel@tonic-gate 		life_began = strtol(system_board_date_st, (char **)NULL, 16);
7420Sstevel@tonic-gate 		if (life_began > *now) {
7430Sstevel@tonic-gate 			no_system_board_date++;
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 	if (no_system_board_date) {
7470Sstevel@tonic-gate 		if (log_system_board_date_error == 0) {
7480Sstevel@tonic-gate 			logerror("No or invalid PROM property "
7490Sstevel@tonic-gate 			    "\"system-board-date\" was found.");
7500Sstevel@tonic-gate 			log_system_board_date_error++;
7510Sstevel@tonic-gate 		}
7520Sstevel@tonic-gate 		life_began = DEFAULT_SYSTEM_BOARD_DATE;
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	life_passed = *now - life_began;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/*
7580Sstevel@tonic-gate 	 * Since we don't keep the date that last free_cycle is ended, we
7590Sstevel@tonic-gate 	 * need to spread (power_cycle_limit - free_cycles) over the entire
7600Sstevel@tonic-gate 	 * 7-year life span instead of (lifetime - date free_cycles ended).
7610Sstevel@tonic-gate 	 */
762*3028Smh27603 	scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) *
763*3028Smh27603 				(power_cycle_limit - free_cycles));
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (no_power_cycles)
7660Sstevel@tonic-gate 		goto ckdone;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate #ifdef DEBUG
7690Sstevel@tonic-gate 	(void) fprintf(stderr, "Actual power_cycles = %d\t"
7700Sstevel@tonic-gate 				"Scaled power_cycles = %d\n",
7710Sstevel@tonic-gate 				power_cycles, scaled_cycles);
7720Sstevel@tonic-gate #endif
7730Sstevel@tonic-gate 	if (power_cycles > scaled_cycles) {
7740Sstevel@tonic-gate 		if (log_no_autoshutdown_warning == 0) {
7750Sstevel@tonic-gate 			logerror("Automatic shutdown has been temporarily "
7760Sstevel@tonic-gate 			    "suspended in order to preserve the reliability "
7770Sstevel@tonic-gate 			    "of this system.");
7780Sstevel@tonic-gate 			log_no_autoshutdown_warning++;
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 		ret = 0;
7810Sstevel@tonic-gate 		goto ckdone;
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate ckdone:
7850Sstevel@tonic-gate 	if (prom_fd != -1)
7860Sstevel@tonic-gate 		close(prom_fd);
7870Sstevel@tonic-gate 	return (ret);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate static void
7910Sstevel@tonic-gate check_idleness(time_t *now, hrtime_t *hr_now)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	/*
7950Sstevel@tonic-gate 	 * Check idleness only when autoshutdown is enabled.
7960Sstevel@tonic-gate 	 */
7970Sstevel@tonic-gate 	if (!autoshutdown_en) {
7980Sstevel@tonic-gate 		checkidle_time = 0;
7990Sstevel@tonic-gate 		return;
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	info->pd_ttychars_idle = check_tty(hr_now, asinfo.ttychars_thold);
8030Sstevel@tonic-gate 	info->pd_loadaverage_idle =
8040Sstevel@tonic-gate 	    check_load_ave(hr_now, asinfo.loadaverage_thold);
8050Sstevel@tonic-gate 	info->pd_diskreads_idle = check_disks(hr_now, asinfo.diskreads_thold);
8060Sstevel@tonic-gate 	info->pd_nfsreqs_idle = check_nfs(hr_now, asinfo.nfsreqs_thold);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate #ifdef DEBUG
8090Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle ttychars for %d secs.\n",
8100Sstevel@tonic-gate 			info->pd_ttychars_idle);
8110Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle loadaverage for %d secs.\n",
8120Sstevel@tonic-gate 			info->pd_loadaverage_idle);
8130Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle diskreads for %d secs.\n",
8140Sstevel@tonic-gate 			info->pd_diskreads_idle);
8150Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle nfsreqs for %d secs.\n",
8160Sstevel@tonic-gate 			info->pd_nfsreqs_idle);
8170Sstevel@tonic-gate #endif
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	checkidle_time = *now + IDLECHK_INTERVAL;
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate static int
8230Sstevel@tonic-gate last_system_activity(hrtime_t *hr_now)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	int	act_idle, latest;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	latest = info->pd_idle_time * 60;
8280Sstevel@tonic-gate 	act_idle = last_tty_activity(hr_now, asinfo.ttychars_thold);
8290Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8300Sstevel@tonic-gate 	act_idle = last_load_ave_activity(hr_now);
8310Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8320Sstevel@tonic-gate 	act_idle = last_disk_activity(hr_now, asinfo.diskreads_thold);
8330Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8340Sstevel@tonic-gate 	act_idle = last_nfs_activity(hr_now, asinfo.nfsreqs_thold);
8350Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	return (latest);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate static int
8410Sstevel@tonic-gate run_idlecheck()
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	char		pm_variable[LLEN];
8440Sstevel@tonic-gate 	char		*cp;
8450Sstevel@tonic-gate 	int		status;
8460Sstevel@tonic-gate 	pid_t		child;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * Reap any child process which has been left over.
8500Sstevel@tonic-gate 	 */
8510Sstevel@tonic-gate 	while (waitpid((pid_t)-1, &status, WNOHANG) > 0);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	/*
8540Sstevel@tonic-gate 	 * Execute the user's idlecheck script and set variable PM_IDLETIME.
8550Sstevel@tonic-gate 	 * Returned exit value is the idle time in minutes.
8560Sstevel@tonic-gate 	 */
8570Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
8580Sstevel@tonic-gate 		(void) sprintf(pm_variable, "PM_IDLETIME=%d",
8590Sstevel@tonic-gate 			info->pd_idle_time);
8600Sstevel@tonic-gate 		(void) putenv(pm_variable);
8610Sstevel@tonic-gate 		cp = strrchr(asinfo.idlecheck_path, '/');
8620Sstevel@tonic-gate 		if (cp == NULL)
8630Sstevel@tonic-gate 			cp = asinfo.idlecheck_path;
8640Sstevel@tonic-gate 		else
8650Sstevel@tonic-gate 			cp++;
8660Sstevel@tonic-gate 		(void) execl(asinfo.idlecheck_path, cp, NULL);
8670Sstevel@tonic-gate 		exit(-1);
8680Sstevel@tonic-gate 	} else if (child == -1) {
8690Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	/*
8730Sstevel@tonic-gate 	 * Wait until the idlecheck program completes.
8740Sstevel@tonic-gate 	 */
8750Sstevel@tonic-gate 	if (waitpid(child, &status, 0) != child) {
8760Sstevel@tonic-gate 		/*
8770Sstevel@tonic-gate 		 * We get here if the calling process gets a signal.
8780Sstevel@tonic-gate 		 */
8790Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (WEXITSTATUS(status) < 0) {
8830Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8840Sstevel@tonic-gate 	} else {
8850Sstevel@tonic-gate 		return (WEXITSTATUS(status) * 60);
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate static void
8900Sstevel@tonic-gate set_alarm(time_t now)
8910Sstevel@tonic-gate {
8920Sstevel@tonic-gate 	time_t	itime, stime, next_time, max_time;
8930Sstevel@tonic-gate 	int	next_alarm;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	max_time = MAX(checkidle_time, shutdown_time);
8960Sstevel@tonic-gate 	if (max_time == 0) {
8970Sstevel@tonic-gate 		(void) alarm(0);
8980Sstevel@tonic-gate 		return;
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 	itime = (checkidle_time == 0) ? max_time : checkidle_time;
9010Sstevel@tonic-gate 	stime = (shutdown_time == 0) ? max_time : shutdown_time;
9020Sstevel@tonic-gate 	next_time = MIN(itime, stime);
9030Sstevel@tonic-gate 	next_alarm = (next_time <= now) ? 1 : (next_time - now);
9040Sstevel@tonic-gate 	(void) alarm(next_alarm);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate #ifdef DEBUG
9070Sstevel@tonic-gate 	(void) fprintf(stderr, "Currently @ %s", ctime(&now));
9080Sstevel@tonic-gate 	(void) fprintf(stderr, "Checkidle in %d secs\n", checkidle_time - now);
9090Sstevel@tonic-gate 	(void) fprintf(stderr, "Shutdown  in %d secs\n", shutdown_time - now);
9100Sstevel@tonic-gate 	(void) fprintf(stderr, "Next alarm goes off in %d secs\n", next_alarm);
9110Sstevel@tonic-gate 	(void) fprintf(stderr, "************************************\n");
9120Sstevel@tonic-gate #endif
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate static int
916*3028Smh27603 poweroff(const char *msg, char **cmd_argv)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate 	struct stat	statbuf;
9190Sstevel@tonic-gate 	pid_t		pid, child;
9200Sstevel@tonic-gate 	struct passwd	*pwd;
9210Sstevel@tonic-gate 	char		*home, *user;
9220Sstevel@tonic-gate 	char		ehome[] = "HOME=";
9230Sstevel@tonic-gate 	char		euser[] = "LOGNAME=";
9240Sstevel@tonic-gate 	int		status;
9250Sstevel@tonic-gate 	char		**ca;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	if (mutex_trylock(&poweroff_mutex) != 0)
9280Sstevel@tonic-gate 		return (0);
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	if (stat("/dev/console", &statbuf) == -1 ||
9310Sstevel@tonic-gate 	    (pwd = getpwuid(statbuf.st_uid)) == NULL) {
9320Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9330Sstevel@tonic-gate 		return (1);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	if (msg)
9370Sstevel@tonic-gate 		syslog(LOG_NOTICE, msg);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	if (*cmd_argv == NULL) {
9400Sstevel@tonic-gate 		logerror("No command to run.");
9410Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9420Sstevel@tonic-gate 		return (1);
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	home = malloc(strlen(pwd->pw_dir) + sizeof (ehome));
9460Sstevel@tonic-gate 	user = malloc(strlen(pwd->pw_name) + sizeof (euser));
9470Sstevel@tonic-gate 	if (home == NULL || user == NULL) {
9480Sstevel@tonic-gate 		free(home);
9490Sstevel@tonic-gate 		free(user);
9500Sstevel@tonic-gate 		logerror("No memory.");
9510Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9520Sstevel@tonic-gate 		return (1);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 	(void) strcpy(home, ehome);
9550Sstevel@tonic-gate 	(void) strcat(home, pwd->pw_dir);
9560Sstevel@tonic-gate 	(void) strcpy(user, euser);
9570Sstevel@tonic-gate 	(void) strcat(user, pwd->pw_name);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/*
9600Sstevel@tonic-gate 	 * Need to simulate the user enviroment, minimaly set HOME, and USER.
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
9630Sstevel@tonic-gate 		(void) putenv(home);
9640Sstevel@tonic-gate 		(void) putenv(user);
9650Sstevel@tonic-gate 		(void) setgid(pwd->pw_gid);
9660Sstevel@tonic-gate 		(void) setuid(pwd->pw_uid);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 		/*
9690Sstevel@tonic-gate 		 * check for shutdown flag and set environment
9700Sstevel@tonic-gate 		 */
9710Sstevel@tonic-gate 		for (ca = cmd_argv; *ca; ca++) {
9720Sstevel@tonic-gate 			if (strcmp("-h", *ca) == 0) {
9730Sstevel@tonic-gate 				(void) putenv("SYSSUSPENDDODEFAULT=");
9740Sstevel@tonic-gate 				break;
9750Sstevel@tonic-gate 			}
9760Sstevel@tonic-gate 		}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 		(void) execv(cmd_argv[0], cmd_argv);
9790Sstevel@tonic-gate 		exit(EXIT_FAILURE);
9800Sstevel@tonic-gate 	} else {
9810Sstevel@tonic-gate 		free(home);
9820Sstevel@tonic-gate 		free(user);
9830Sstevel@tonic-gate 		if (child == -1) {
9840Sstevel@tonic-gate 			mutex_unlock(&poweroff_mutex);
9850Sstevel@tonic-gate 			return (1);
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 	}
9880Sstevel@tonic-gate 	pid = 0;
9890Sstevel@tonic-gate 	while (pid != child)
9900Sstevel@tonic-gate 		pid = wait(&status);
9910Sstevel@tonic-gate 	if (WEXITSTATUS(status)) {
9920Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "Failed to exec \"%s\".", cmd_argv[0]);
9930Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9940Sstevel@tonic-gate 		return (1);
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	mutex_unlock(&poweroff_mutex);
9980Sstevel@tonic-gate 	return (0);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate #define	PBUFSIZE	256
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate /*
10040Sstevel@tonic-gate  * Gets the value of a prom property at either root or options node.  It
10050Sstevel@tonic-gate  * returns 1 if it is successful, otherwise it returns 0 .
10060Sstevel@tonic-gate  */
10070Sstevel@tonic-gate static int
10080Sstevel@tonic-gate get_prom(int prom_fd, prom_node_t node_name,
10090Sstevel@tonic-gate 	char *property_name, char *property_value, size_t len)
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate 	union {
10120Sstevel@tonic-gate 		char buf[PBUFSIZE + sizeof (uint_t)];
10130Sstevel@tonic-gate 		struct openpromio opp;
10140Sstevel@tonic-gate 	} oppbuf;
10150Sstevel@tonic-gate 	register struct openpromio *opp = &(oppbuf.opp);
10160Sstevel@tonic-gate 	int	got_it = 0;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	if (prom_fd == -1) {
10190Sstevel@tonic-gate 		return (0);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	switch (node_name) {
10230Sstevel@tonic-gate 	case root:
10240Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
10250Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10260Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNEXT, opp) < 0) {
10270Sstevel@tonic-gate 			return (0);
10280Sstevel@tonic-gate 		}
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		/*
10310Sstevel@tonic-gate 		 * Passing null string will give us the first property.
10320Sstevel@tonic-gate 		 */
10330Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
10340Sstevel@tonic-gate 		do {
10350Sstevel@tonic-gate 			opp->oprom_size = PBUFSIZE;
10360Sstevel@tonic-gate 			if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) {
10370Sstevel@tonic-gate 				return (0);
10380Sstevel@tonic-gate 			}
10390Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, property_name) == 0) {
10400Sstevel@tonic-gate 				got_it++;
10410Sstevel@tonic-gate 				break;
10420Sstevel@tonic-gate 			}
10430Sstevel@tonic-gate 		} while (opp->oprom_size > 0);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 		if (!got_it) {
10460Sstevel@tonic-gate 			return (0);
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 		if (got_it && property_value == NULL) {
10490Sstevel@tonic-gate 			return (1);
10500Sstevel@tonic-gate 		}
10510Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10520Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) {
10530Sstevel@tonic-gate 			return (0);
10540Sstevel@tonic-gate 		}
10550Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
10560Sstevel@tonic-gate 			*property_value = '\0';
10570Sstevel@tonic-gate 		} else {
10580Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
10590Sstevel@tonic-gate 		}
10600Sstevel@tonic-gate 		break;
10610Sstevel@tonic-gate 	case options:
10620Sstevel@tonic-gate 		estrcpy(opp->oprom_array, property_name, PBUFSIZE);
10630Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10640Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
10650Sstevel@tonic-gate 			return (0);
10660Sstevel@tonic-gate 		}
10670Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
10680Sstevel@tonic-gate 			return (0);
10690Sstevel@tonic-gate 		}
10700Sstevel@tonic-gate 		if (property_value != NULL) {
10710Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 		break;
10740Sstevel@tonic-gate 	default:
10750Sstevel@tonic-gate 		logerror("Only root node and options node are supported.\n");
10760Sstevel@tonic-gate 		return (0);
10770Sstevel@tonic-gate 	}
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	return (1);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate #define	isspace(ch)	((ch) == ' ' || (ch) == '\t')
10830Sstevel@tonic-gate #define	iseol(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate /*ARGSUSED*/
10860Sstevel@tonic-gate static void
10870Sstevel@tonic-gate power_button_monitor(void *arg)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	struct pollfd pfd;
10900Sstevel@tonic-gate 	int events;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) {
10930Sstevel@tonic-gate 		logerror("Failed to monitor the power button.");
10940Sstevel@tonic-gate 		thr_exit((void *) 0);
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	pfd.fd = pb_fd;
10980Sstevel@tonic-gate 	pfd.events = POLLIN;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	/*CONSTCOND*/
11010Sstevel@tonic-gate 	while (1) {
11020Sstevel@tonic-gate 		if (poll(&pfd, 1, INFTIM) == -1) {
11030Sstevel@tonic-gate 			logerror("Failed to poll for power button events.");
11040Sstevel@tonic-gate 			thr_exit((void *) 0);
11050Sstevel@tonic-gate 		}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 		if (!(pfd.revents & POLLIN))
11080Sstevel@tonic-gate 			continue;
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
11110Sstevel@tonic-gate 			logerror("Failed to get power button events.");
11120Sstevel@tonic-gate 			thr_exit((void *) 0);
11130Sstevel@tonic-gate 		}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 		if ((events & PB_BUTTON_PRESS) &&
11160Sstevel@tonic-gate 		    (poweroff(NULL, power_button_cmd) != 0)) {
11170Sstevel@tonic-gate 			logerror("Power button is pressed, powering "
11180Sstevel@tonic-gate 			    "down the system!");
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 			/*
11210Sstevel@tonic-gate 			 * Send SIGPWR signal to the init process to
11220Sstevel@tonic-gate 			 * shut down the system.
11230Sstevel@tonic-gate 			 */
11240Sstevel@tonic-gate 			if (kill(1, SIGPWR) == -1)
11250Sstevel@tonic-gate 				(void) uadmin(A_SHUTDOWN, AD_POWEROFF, 0);
11260Sstevel@tonic-gate 		}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 		/*
11290Sstevel@tonic-gate 		 * Clear any power button event that has happened
11300Sstevel@tonic-gate 		 * meanwhile we were busy processing the last one.
11310Sstevel@tonic-gate 		 */
11320Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
11330Sstevel@tonic-gate 			logerror("Failed to get power button events.");
11340Sstevel@tonic-gate 			thr_exit((void *) 0);
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 	}
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate #ifdef sparc
11400Sstevel@tonic-gate static void
11410Sstevel@tonic-gate do_attach(void)
11420Sstevel@tonic-gate {
11430Sstevel@tonic-gate 	if (read_cpr_config() < 0)
11440Sstevel@tonic-gate 		return;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	/*
11470Sstevel@tonic-gate 	 * If autopm behavior is explicitly enabled for energystar-v2, or
11480Sstevel@tonic-gate 	 * set to default for energystar-v3, create a new thread to attach
11490Sstevel@tonic-gate 	 * all devices.
11500Sstevel@tonic-gate 	 */
11510Sstevel@tonic-gate 	estar_v3_prop = asinfo.is_autopm_default;
11520Sstevel@tonic-gate 	if ((strcmp(asinfo.apm_behavior, "enable") == 0) ||
11530Sstevel@tonic-gate 	    (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) {
11540Sstevel@tonic-gate 		if (thr_create(NULL, NULL, attach_devices, NULL,
11550Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
11560Sstevel@tonic-gate 			logerror("Unable to create thread to attach devices.");
11570Sstevel@tonic-gate 		}
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate /*ARGSUSED*/
11620Sstevel@tonic-gate static void *
11630Sstevel@tonic-gate attach_devices(void *arg)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate 	di_node_t root_node;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	sleep(60);	/* let booting finish first */
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) {
11700Sstevel@tonic-gate 		logerror("Failed to attach devices.");
11710Sstevel@tonic-gate 		return (NULL);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 	di_fini(root_node);
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	/*
11760Sstevel@tonic-gate 	 * Unload all the modules.
11770Sstevel@tonic-gate 	 */
11780Sstevel@tonic-gate 	(void) modctl(MODUNLOAD, 0);
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	return (NULL);
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate #endif
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate /*
11860Sstevel@tonic-gate  * Create a file which will contain our pid.  Pmconfig will check this file
11870Sstevel@tonic-gate  * to see if we are running and can use the pid to signal us.  Returns the
11880Sstevel@tonic-gate  * file descriptor if successful, -1 otherwise.
11890Sstevel@tonic-gate  *
11900Sstevel@tonic-gate  * Note: Deal with attempt to launch multiple instances and also with existence
11910Sstevel@tonic-gate  * of an obsolete pid file caused by an earlier abort.
11920Sstevel@tonic-gate  */
11930Sstevel@tonic-gate static int
11940Sstevel@tonic-gate open_pidfile(char *me)
11950Sstevel@tonic-gate {
11960Sstevel@tonic-gate 	int fd;
1197*3028Smh27603 	const char *e1 = "%s: Cannot open pid file for read: ";
1198*3028Smh27603 	const char *e2 = "%s: Cannot unlink obsolete pid file: ";
1199*3028Smh27603 	const char *e3 = "%s: Cannot open /proc for pid %ld: ";
1200*3028Smh27603 	const char *e4 = "%s: Cannot read /proc for pid %ld: ";
1201*3028Smh27603 	const char *e5 = "%s: Another instance (pid %ld) is trying to exit"
12020Sstevel@tonic-gate 			"and may be hung.  Please contact sysadmin.\n";
1203*3028Smh27603 	const char *e6 = "%s: Another daemon is running\n";
1204*3028Smh27603 	const char *e7 = "%s: Cannot create pid file: ";
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate again:
12070Sstevel@tonic-gate 	if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) {
12080Sstevel@tonic-gate 		if (errno  == EEXIST) {
12090Sstevel@tonic-gate 			FILE *fp;
12100Sstevel@tonic-gate 			int ps_fd;
12110Sstevel@tonic-gate 			pid_t pid;
12120Sstevel@tonic-gate 			psinfo_t ps_info;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 			if ((fp = fopen(pidpath, "r")) == NULL) {
12150Sstevel@tonic-gate 				(void) fprintf(stderr, e1, me);
12160Sstevel@tonic-gate 				perror(NULL);
12170Sstevel@tonic-gate 				return (-1);
12180Sstevel@tonic-gate 			}
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 			/* Read the pid */
12210Sstevel@tonic-gate 			pid = (pid_t)-1;
12220Sstevel@tonic-gate 			(void) fscanf(fp, "%ld", &pid);
12230Sstevel@tonic-gate 			(void) fclose(fp);
12240Sstevel@tonic-gate 			if (pid == -1) {
12250Sstevel@tonic-gate 				if (unlink(pidpath) == -1) {
12260Sstevel@tonic-gate 					(void) fprintf(stderr, e2, me);
12270Sstevel@tonic-gate 					perror(NULL);
12280Sstevel@tonic-gate 					return (-1);
12290Sstevel@tonic-gate 				} else /* try without corrupted file */
12300Sstevel@tonic-gate 					goto again;
12310Sstevel@tonic-gate 			}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 			/* Is pid for a running process? */
12340Sstevel@tonic-gate 			(void) sprintf(scratch, "/proc/%ld/psinfo", pid);
12350Sstevel@tonic-gate 			ps_fd = open(scratch, O_RDONLY | O_NDELAY);
12360Sstevel@tonic-gate 			if (ps_fd == -1) {
12370Sstevel@tonic-gate 				if (errno == ENOENT) {
12380Sstevel@tonic-gate 					if (unlink(pidpath) == -1) {
12390Sstevel@tonic-gate 						(void) fprintf(stderr, e2, me);
12400Sstevel@tonic-gate 						perror(NULL);
12410Sstevel@tonic-gate 						return (-1);
12420Sstevel@tonic-gate 					} else	/* try without obsolete file */
12430Sstevel@tonic-gate 						goto again;
12440Sstevel@tonic-gate 				}
12450Sstevel@tonic-gate 				(void) fprintf(stderr, e3, me, pid);
12460Sstevel@tonic-gate 				return (-1);
12470Sstevel@tonic-gate 			}
12480Sstevel@tonic-gate 			if (read(ps_fd, &ps_info,
12490Sstevel@tonic-gate 			    sizeof (ps_info)) != sizeof (ps_info)) {
12500Sstevel@tonic-gate 				(void) fprintf(stderr, e4, me, pid);
12510Sstevel@tonic-gate 				perror(NULL);
12520Sstevel@tonic-gate 				(void) close(ps_fd);
12530Sstevel@tonic-gate 				return (-1);
12540Sstevel@tonic-gate 			}
12550Sstevel@tonic-gate 			(void) close(ps_fd);
12560Sstevel@tonic-gate 			if (ps_info.pr_nlwp == 0) {	/* defunct process */
12570Sstevel@tonic-gate 				(void) fprintf(stderr, e5, me, pid);
12580Sstevel@tonic-gate 				return (-1);
12590Sstevel@tonic-gate 			} else {	/* instance of daemon already running */
12600Sstevel@tonic-gate 				(void) fprintf(stderr, e6, me);
12610Sstevel@tonic-gate 				return (-1);
12620Sstevel@tonic-gate 			}
12630Sstevel@tonic-gate 		} else {	/* create failure not due to existing file */
12640Sstevel@tonic-gate 			(void) fprintf(stderr, e7, me);
12650Sstevel@tonic-gate 			perror(NULL);
12660Sstevel@tonic-gate 			return (-1);
12670Sstevel@tonic-gate 		}
12680Sstevel@tonic-gate 	}
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	(void) fchown(fd, (uid_t)-1, (gid_t)0);
12710Sstevel@tonic-gate 	return (fd);
12720Sstevel@tonic-gate }
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate  * Write a pid to the pid file.  Report errors to syslog.
12760Sstevel@tonic-gate  *
12770Sstevel@tonic-gate  */
12780Sstevel@tonic-gate static int
12790Sstevel@tonic-gate write_pidfile(int fd, pid_t pid)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	int	len;
12820Sstevel@tonic-gate 	int	rc = 0;			/* assume success */
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	len = sprintf(scratch, "%ld\n", pid);
12850Sstevel@tonic-gate 	if (write(fd, scratch, len) != len) {
12860Sstevel@tonic-gate 		logerror("Cannot write pid file: %s", strerror(errno));
12870Sstevel@tonic-gate 		rc = -1;
12880Sstevel@tonic-gate 	}
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	return (rc);
12910Sstevel@tonic-gate }
1292