xref: /onnv-gate/usr/src/cmd/power/powerd.c (revision 11053:f33a1c7f3155)
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
53028Smh27603  * Common Development and Distribution License (the "License").
63028Smh27603  * 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 /*
228940SRandy.Fishel@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>			/* Standard */
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <fcntl.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <time.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <pwd.h>
340Sstevel@tonic-gate #include <dirent.h>
350Sstevel@tonic-gate #include <thread.h>
360Sstevel@tonic-gate #include <limits.h>
370Sstevel@tonic-gate #include <sys/todio.h>			/* Time-Of-Day chip */
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/wait.h>
400Sstevel@tonic-gate #include <sys/ipc.h>			/* IPC functions */
410Sstevel@tonic-gate #include <signal.h>			/* signal handling */
420Sstevel@tonic-gate #include <syslog.h>
430Sstevel@tonic-gate #include <unistd.h>
440Sstevel@tonic-gate #include <libdevinfo.h>
450Sstevel@tonic-gate #include <poll.h>
460Sstevel@tonic-gate #include <sys/pm.h>			/* power management driver */
470Sstevel@tonic-gate #include <sys/uadmin.h>
480Sstevel@tonic-gate #include <sys/openpromio.h>		/* for prom access */
490Sstevel@tonic-gate #include <sys/sysmacros.h>		/* for MIN & MAX macros */
500Sstevel@tonic-gate #include <sys/modctl.h>
510Sstevel@tonic-gate #include <sys/stropts.h>		/* for INFTIM */
520Sstevel@tonic-gate #include <sys/pbio.h>
530Sstevel@tonic-gate #include <sys/cpr.h>
545295Srandyf #include <sys/srn.h>
550Sstevel@tonic-gate #include <stdarg.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include "powerd.h"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* External Functions */
600Sstevel@tonic-gate extern struct tm *localtime_r(const time_t *, struct tm *);
610Sstevel@tonic-gate extern void sysstat_init(void);
620Sstevel@tonic-gate extern int check_tty(hrtime_t *, int);
630Sstevel@tonic-gate extern int check_disks(hrtime_t *, int);
640Sstevel@tonic-gate extern int check_load_ave(hrtime_t *, float);
650Sstevel@tonic-gate extern int check_nfs(hrtime_t *, int);
660Sstevel@tonic-gate extern int last_disk_activity(hrtime_t *, int);
670Sstevel@tonic-gate extern int last_tty_activity(hrtime_t *, int);
680Sstevel@tonic-gate extern int last_load_ave_activity(hrtime_t *);
690Sstevel@tonic-gate extern int last_nfs_activity(hrtime_t *, int);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	PM		"/dev/pm"
720Sstevel@tonic-gate #define	TOD		"/dev/tod"
730Sstevel@tonic-gate #define	PROM		"/dev/openprom"
740Sstevel@tonic-gate #define	PB		"/dev/power_button"
755295Srandyf #define	SRN		"/dev/srn"
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;
1110Sstevel@tonic-gate static int		estar_v3_prop;
1120Sstevel@tonic-gate static int		log_power_cycles_error = 0;
1130Sstevel@tonic-gate static int		log_system_board_date_error = 0;
1140Sstevel@tonic-gate static int		log_no_autoshutdown_warning = 0;
1150Sstevel@tonic-gate static mutex_t		poweroff_mutex;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static char *autoshutdown_cmd[] = {
1188940SRandy.Fishel@Sun.COM 	"/usr/bin/sys-suspend",
1190Sstevel@tonic-gate 	"-n", "-d", ":0", NULL
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static char *power_button_cmd[] = {
1238940SRandy.Fishel@Sun.COM 	"/usr/bin/sys-suspend",
1240Sstevel@tonic-gate 	"-h", "-d", ":0", NULL
1250Sstevel@tonic-gate };
1260Sstevel@tonic-gate 
1275295Srandyf static char *autoS3_cmd[] = {
1288940SRandy.Fishel@Sun.COM 	"/usr/bin/sys-suspend",
1295295Srandyf 	"-n", "-d", ":0", NULL
1305295Srandyf };
1315295Srandyf 
1320Sstevel@tonic-gate static char pidpath[] = PIDPATH;
1330Sstevel@tonic-gate static char scratch[PATH_MAX];
1340Sstevel@tonic-gate static char *prog;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /* Local Functions */
1370Sstevel@tonic-gate static void alarm_handler(int);
1380Sstevel@tonic-gate static void thaw_handler(int);
1390Sstevel@tonic-gate static void kill_handler(int);
1400Sstevel@tonic-gate static void work_handler(int);
1410Sstevel@tonic-gate static void check_shutdown(time_t *, hrtime_t *);
1420Sstevel@tonic-gate static void check_idleness(time_t *, hrtime_t *);
1430Sstevel@tonic-gate static int last_system_activity(hrtime_t *);
1440Sstevel@tonic-gate static int run_idlecheck(void);
1450Sstevel@tonic-gate static void set_alarm(time_t);
1463028Smh27603 static int poweroff(const char *, char **);
1470Sstevel@tonic-gate static int is_ok2shutdown(time_t *);
1480Sstevel@tonic-gate static int get_prom(int, prom_node_t, char *, char *, size_t);
1490Sstevel@tonic-gate static void power_button_monitor(void *);
1500Sstevel@tonic-gate static int open_pidfile(char *);
1510Sstevel@tonic-gate static int write_pidfile(int, pid_t);
1520Sstevel@tonic-gate static int read_cpr_config(void);
1530Sstevel@tonic-gate static void system_activity_monitor(void);
1545295Srandyf static void autos3_monitor(void);
1550Sstevel@tonic-gate static void do_attach(void);
1560Sstevel@tonic-gate static void *attach_devices(void *);
1575295Srandyf static int powerd_debug;
1580Sstevel@tonic-gate 
1593028Smh27603 /* PRINTFLIKE1 */
1600Sstevel@tonic-gate static void
logerror(const char * fmt,...)1613028Smh27603 logerror(const char *fmt, ...)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	va_list args;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	va_start(args, fmt);
1660Sstevel@tonic-gate 	if (broadcast)
1670Sstevel@tonic-gate 		vsyslog(LOG_ERR, fmt, args);
1680Sstevel@tonic-gate 	va_end(args);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate static void
estrcpy(char * dst,char * src,size_t dlen)1730Sstevel@tonic-gate estrcpy(char *dst, char *src, size_t dlen)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	size_t slen;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	slen = strlcpy(dst, src, dlen);
1780Sstevel@tonic-gate 	if (slen >= dlen) {
1790Sstevel@tonic-gate 		logerror("%s: string too long \"%s ...\"\n"
1800Sstevel@tonic-gate 		    "(len %d, max %d)\n", prog, dst, slen, dlen - 1);
1810Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate int
main(int argc,char * argv[])1870Sstevel@tonic-gate main(int argc, char *argv[])
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	pid_t		pid;
1900Sstevel@tonic-gate 	int		pm_fd;
1910Sstevel@tonic-gate 	struct sigaction act;
1920Sstevel@tonic-gate 	sigset_t	sigmask;
1930Sstevel@tonic-gate 	int		c;
1940Sstevel@tonic-gate 	char		errmsg[PATH_MAX + 64];
1950Sstevel@tonic-gate 	int		pid_fd;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	prog = argv[0];
1980Sstevel@tonic-gate 	if (geteuid() != 0) {
1990Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: Must be root\n", prog);
2000Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if ((pid_fd = open_pidfile(prog)) ==  -1)
2040Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 * Process options
2080Sstevel@tonic-gate 	 */
2090Sstevel@tonic-gate 	broadcast = 1;
2105295Srandyf 	while ((c = getopt(argc, argv, "nd")) != EOF) {
2110Sstevel@tonic-gate 		switch (c) {
2125295Srandyf 		case 'd':
2135295Srandyf 			powerd_debug = 1;
2145295Srandyf 			break;
2150Sstevel@tonic-gate 		case 'n':
2160Sstevel@tonic-gate 			broadcast = 0;
2170Sstevel@tonic-gate 			break;
2180Sstevel@tonic-gate 		case '?':
2190Sstevel@tonic-gate 			(void) fprintf(stderr, "Usage: %s [-n]\n", prog);
2200Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	pm_fd = open(PM, O_RDWR);
2250Sstevel@tonic-gate 	if (pm_fd == -1) {
2263028Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM);
2270Sstevel@tonic-gate 		perror(errmsg);
2280Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 	(void) close(pm_fd);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	/*
2330Sstevel@tonic-gate 	 * Initialize mutex lock used to insure only one command to
2340Sstevel@tonic-gate 	 * run at a time.
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) {
2370Sstevel@tonic-gate 		(void) fprintf(stderr,
2385295Srandyf 		    "%s: Unable to initialize mutex lock\n", prog);
2390Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) {
2433028Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog);
2440Sstevel@tonic-gate 		perror(errmsg);
2450Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * Daemon is set to go...
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	if ((pid = fork()) < 0)
2520Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2530Sstevel@tonic-gate 	else if (pid != 0)
2540Sstevel@tonic-gate 		exit(EXIT_SUCCESS);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	pid = getpid();
2570Sstevel@tonic-gate 	openlog(prog, 0, LOG_DAEMON);
2580Sstevel@tonic-gate 	if (write_pidfile(pid_fd, pid) == -1)	/* logs errors on failure */
2590Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2600Sstevel@tonic-gate 	(void) close(pid_fd);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * Close all the parent's file descriptors (Bug 1225843).
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	closefrom(0);
2660Sstevel@tonic-gate 	(void) setsid();
2670Sstevel@tonic-gate 	(void) chdir("/");
2680Sstevel@tonic-gate 	(void) umask(0);
2690Sstevel@tonic-gate #ifdef DEBUG
2700Sstevel@tonic-gate 	/*
2710Sstevel@tonic-gate 	 * Connect stdout to the console.
2720Sstevel@tonic-gate 	 */
2730Sstevel@tonic-gate 	if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) {
2740Sstevel@tonic-gate 		logerror("Unable to connect to the console.");
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate #endif
2770Sstevel@tonic-gate 	info->pd_flags = PD_AC;
2780Sstevel@tonic-gate 	info->pd_idle_time = -1;
2790Sstevel@tonic-gate 	info->pd_start_time = 0;
2800Sstevel@tonic-gate 	info->pd_finish_time = 0;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/*
2830Sstevel@tonic-gate 	 * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
2840Sstevel@tonic-gate 	 * any time
2850Sstevel@tonic-gate 	 */
2860Sstevel@tonic-gate 	act.sa_handler = kill_handler;
2870Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
2880Sstevel@tonic-gate 	act.sa_flags = 0;
2890Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &act, NULL);
2900Sstevel@tonic-gate 	(void) sigaction(SIGINT, &act, NULL);
2910Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &act, NULL);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	(void) sigfillset(&sigmask);
2940Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGQUIT);
2950Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGINT);
2960Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTERM);
2970Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/*
3000Sstevel@tonic-gate 	 * If "power_button" device node can be opened, create a new
3010Sstevel@tonic-gate 	 * thread to monitor the power button.
3020Sstevel@tonic-gate 	 */
3030Sstevel@tonic-gate 	if ((pb_fd = open(PB, O_RDONLY)) != -1) {
3045295Srandyf 		if (powerd_debug)
3055295Srandyf 			logerror("powerd starting power button monitor.");
3060Sstevel@tonic-gate 		if (thr_create(NULL, NULL,
3070Sstevel@tonic-gate 		    (void *(*)(void *))power_button_monitor, NULL,
3080Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
3090Sstevel@tonic-gate 			logerror("Unable to monitor system's power button.");
3100Sstevel@tonic-gate 		}
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	do_attach();
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	/*
3160Sstevel@tonic-gate 	 * Create a new thread to monitor system activity and suspend
3170Sstevel@tonic-gate 	 * system if idle.
3180Sstevel@tonic-gate 	 */
3195295Srandyf 	if (powerd_debug)
3205295Srandyf 		logerror("powerd starting system activity monitor.");
3210Sstevel@tonic-gate 	if (thr_create(NULL, NULL,
3220Sstevel@tonic-gate 	    (void *(*)(void *))system_activity_monitor, NULL,
3230Sstevel@tonic-gate 	    THR_DAEMON, NULL) != 0) {
3240Sstevel@tonic-gate 		logerror("Unable to create thread to monitor system activity.");
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	/*
3285295Srandyf 	 * Create a new thread to handle autos3 trigger
3295295Srandyf 	 */
3305295Srandyf 	if (powerd_debug)
3315295Srandyf 		logerror("powerd starting autos3 monitor.");
3325295Srandyf 	if (thr_create(NULL, NULL,
3335295Srandyf 	    (void *(*)(void *))autos3_monitor, NULL, THR_DAEMON, NULL) != 0) {
3345295Srandyf 		logerror("Unable to create thread to monitor autos3 activity.");
3355295Srandyf 	}
3365295Srandyf 
3375295Srandyf 	/*
3380Sstevel@tonic-gate 	 * Block until we receive an explicit terminate signal
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	(void) sigsuspend(&sigmask);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	return (1);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate static void
system_activity_monitor(void)3460Sstevel@tonic-gate system_activity_monitor(void)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	struct sigaction act;
3490Sstevel@tonic-gate 	sigset_t sigmask;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * Setup for gathering system's statistic.
3530Sstevel@tonic-gate 	 */
3540Sstevel@tonic-gate 	sysstat_init();
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3570Sstevel@tonic-gate 	 * In addition to the SIGQUIT, SIGINT and SIGTERM signals already
3580Sstevel@tonic-gate 	 * being handled, this thread also needs to handle SIGHUP, SIGALRM
3590Sstevel@tonic-gate 	 * and SIGTHAW signals.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
3620Sstevel@tonic-gate 	act.sa_flags = 0;
3630Sstevel@tonic-gate 	act.sa_handler = alarm_handler;
3640Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &act, NULL);
3650Sstevel@tonic-gate 	act.sa_handler = work_handler;
3660Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &act, NULL);
3670Sstevel@tonic-gate 	act.sa_handler = thaw_handler;
3680Sstevel@tonic-gate 	(void) sigaction(SIGTHAW, &act, NULL);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/*
3710Sstevel@tonic-gate 	 * Invoke work_handler with a dummy SIGHUP signal to read
3720Sstevel@tonic-gate 	 * cpr config file, get autoshutdown properties and schedule
3730Sstevel@tonic-gate 	 * an alarm if needed.
3740Sstevel@tonic-gate 	 */
3750Sstevel@tonic-gate 	work_handler(SIGHUP);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * Wait for signal to read file
3790Sstevel@tonic-gate 	 */
3800Sstevel@tonic-gate 	(void) thr_sigsetmask(0, 0, &sigmask);
3810Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGHUP);
3820Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGALRM);
3830Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTHAW);
3840Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
3850Sstevel@tonic-gate 	do {
3860Sstevel@tonic-gate 		(void) sigsuspend(&sigmask);
3870Sstevel@tonic-gate 	} while (errno == EINTR);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3905295Srandyf static void
autos3_monitor(void)3915295Srandyf autos3_monitor(void)
3925295Srandyf {
3935295Srandyf 	struct pollfd poll_fd;
3945295Srandyf 	srn_event_info_t srn_event;		/* contains suspend type */
3955295Srandyf 	int fd, ret;
3965295Srandyf 
3975295Srandyf 	fd = open(SRN, O_RDWR|O_EXCL|O_NDELAY);
3985295Srandyf 	if (fd == -1) {
3995295Srandyf 		logerror("Unable to open %s: %s", SRN, strerror(errno));
4005295Srandyf 		thr_exit((void *) errno);
4015295Srandyf 	}
4025295Srandyf 	logerror("Able to open %s", SRN);
4035295Srandyf 
4045295Srandyf 	/*
4055295Srandyf 	 * Tell device we want the special sauce
4065295Srandyf 	 */
4075295Srandyf 	ret = ioctl(fd, SRN_IOC_AUTOSX, NULL);
4085295Srandyf 	if (ret == -1) {
4095295Srandyf 		logerror("Ioctl SRN_IOC_AUTOSX failed: %s", strerror(errno));
410*11053SSurya.Prakki@Sun.COM 		(void) close(fd);
4115295Srandyf 		thr_exit((void *) errno);
4125295Srandyf 	}
4135295Srandyf 	poll_fd.fd = fd;
4145295Srandyf 	/*CONSTCOND*/
4155295Srandyf 	while (1) {
4165295Srandyf 		poll_fd.revents = 0;
4175295Srandyf 		poll_fd.events = POLLIN;
4185295Srandyf 		if (poll(&poll_fd, 1, -1) < 0) {
4195295Srandyf 			switch (errno) {
4205295Srandyf 			case EINTR:
4215295Srandyf 			case EAGAIN:
4225295Srandyf 				continue;
4235295Srandyf 			default:
4245295Srandyf 				logerror("Poll error: %s", strerror(errno));
425*11053SSurya.Prakki@Sun.COM 				(void) close(fd);
4265295Srandyf 				thr_exit((void *) errno);
4275295Srandyf 			}
4285295Srandyf 		}
4295295Srandyf 
4305295Srandyf 		ret = ioctl(fd, SRN_IOC_NEXTEVENT, &srn_event);
4315295Srandyf 		if (ret == -1) {
4325295Srandyf 			logerror("ioctl error: %s", strerror(errno));
433*11053SSurya.Prakki@Sun.COM 			(void) close(fd);
4345295Srandyf 			thr_exit((void *) errno);
4355295Srandyf 		}
4365295Srandyf 		switch (srn_event.ae_type) {
4375295Srandyf 		case 3:			/* S3 */
4385295Srandyf 			if (powerd_debug)
4395295Srandyf 				logerror("ioctl returns type: %d",
4405295Srandyf 				    srn_event.ae_type);
4415295Srandyf 			break;
4425295Srandyf 		default:
4435295Srandyf 			logerror("Unsupported target state %d",
4445295Srandyf 			    srn_event.ae_type);
4455295Srandyf 			continue;
4465295Srandyf 		}
4475295Srandyf 		(void) poweroff("AutoS3", autoS3_cmd);
4485295Srandyf 		continue;
4495295Srandyf 	}
4505295Srandyf }
4515295Srandyf 
4520Sstevel@tonic-gate static int
read_cpr_config(void)4530Sstevel@tonic-gate read_cpr_config(void)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	int	asfd;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	if ((asfd = open(CPR_CONFIG, O_RDONLY)) < 0) {
4580Sstevel@tonic-gate 		logerror("Unable to open CPR config file '%s'", CPR_CONFIG);
4590Sstevel@tonic-gate 		return (-1);
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if (read(asfd, (void *)&asinfo, sizeof (asinfo)) != sizeof (asinfo)) {
4630Sstevel@tonic-gate 		logerror("Unable to read CPR config file '%s'", CPR_CONFIG);
464*11053SSurya.Prakki@Sun.COM 		(void) close(asfd);
4650Sstevel@tonic-gate 		return (-1);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	(void) close(asfd);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	return (0);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /*ARGSUSED*/
4740Sstevel@tonic-gate static void
thaw_handler(int sig)4750Sstevel@tonic-gate thaw_handler(int sig)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	start_calc  = 0;
4780Sstevel@tonic-gate 	last_resume = time(NULL);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate /*ARGSUSED*/
4820Sstevel@tonic-gate static void
kill_handler(int sig)4830Sstevel@tonic-gate kill_handler(int sig)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate 	int ret_code = EXIT_SUCCESS;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/*
4880Sstevel@tonic-gate 	 * Free resources
4890Sstevel@tonic-gate 	 */
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	free(info);
4920Sstevel@tonic-gate 	if (pb_fd != -1) {
4930Sstevel@tonic-gate 		(void) close(pb_fd);
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	(void) mutex_destroy(&poweroff_mutex);
4960Sstevel@tonic-gate 	(void) unlink(pidpath);
4970Sstevel@tonic-gate 	closelog();
4980Sstevel@tonic-gate 	exit(ret_code);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /*ARGSUSED*/
5020Sstevel@tonic-gate static void
alarm_handler(int sig)5030Sstevel@tonic-gate alarm_handler(int sig)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate 	time_t		now;
5060Sstevel@tonic-gate 	hrtime_t	hr_now;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	now = time(NULL);
5090Sstevel@tonic-gate 	hr_now = gethrtime();
5100Sstevel@tonic-gate 	if (checkidle_time <= now && checkidle_time != 0)
5110Sstevel@tonic-gate 		check_idleness(&now, &hr_now);
5120Sstevel@tonic-gate 	if (shutdown_time <= now && shutdown_time != 0)
5130Sstevel@tonic-gate 		check_shutdown(&now, &hr_now);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	set_alarm(now);
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate /*ARGSUSED*/
5190Sstevel@tonic-gate static void
work_handler(int sig)5200Sstevel@tonic-gate work_handler(int sig)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	time_t		now;
5230Sstevel@tonic-gate 	hrtime_t	hr_now;
5240Sstevel@tonic-gate 	struct stat	stat_buf;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	do_idlecheck = 0;
5270Sstevel@tonic-gate 	info->pd_flags = PD_AC;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Parse the config file for autoshutdown and idleness entries.
5310Sstevel@tonic-gate 	 */
5320Sstevel@tonic-gate 	if (read_cpr_config() < 0)
5330Sstevel@tonic-gate 		return;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/*
5360Sstevel@tonic-gate 	 * Since Oct. 1, 1995, any new system shipped had root
5370Sstevel@tonic-gate 	 * property "energystar-v2" defined in its prom.  Systems
5380Sstevel@tonic-gate 	 * shipped after July 1, 1999, will have "energystar-v3"
5390Sstevel@tonic-gate 	 * property.
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	estar_v2_prop = asinfo.is_cpr_default;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	info->pd_flags |= asinfo.is_autowakeup_capable;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (strlen(asinfo.idlecheck_path) > 0) {
5460Sstevel@tonic-gate 		if (stat(asinfo.idlecheck_path, &stat_buf) != 0) {
5470Sstevel@tonic-gate 			logerror("unable to access idlecheck program \"%s\".",
5480Sstevel@tonic-gate 			    asinfo.idlecheck_path);
5490Sstevel@tonic-gate 		} else if (!(stat_buf.st_mode & S_IXUSR)) {
5500Sstevel@tonic-gate 			logerror("idlecheck program \"%s\" is not executable.",
5510Sstevel@tonic-gate 			    asinfo.idlecheck_path);
5520Sstevel@tonic-gate 		} else {
5530Sstevel@tonic-gate 			do_idlecheck = 1;
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (strlen(asinfo.as_behavior) == 0 ||
5580Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "noshutdown") == 0 ||
5590Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "unconfigured") == 0) {
5600Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
5610Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "default") == 0) {
5620Sstevel@tonic-gate 		info->pd_autoshutdown = estar_v2_prop;
5630Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "shutdown") == 0 ||
5645295Srandyf 	    strcmp(asinfo.as_behavior, "autowakeup") == 0) {
5650Sstevel@tonic-gate 		info->pd_autoshutdown = asinfo.is_cpr_capable;
5660Sstevel@tonic-gate 	} else {
5670Sstevel@tonic-gate 		logerror("autoshutdown behavior \"%s\" unrecognized.",
5680Sstevel@tonic-gate 		    asinfo.as_behavior);
5690Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	if (info->pd_autoshutdown) {
5730Sstevel@tonic-gate 		info->pd_idle_time = asinfo.as_idle;
5740Sstevel@tonic-gate 		info->pd_start_time =
5750Sstevel@tonic-gate 		    (asinfo.as_sh * 60 + asinfo.as_sm) % DAYS_TO_MINS;
5760Sstevel@tonic-gate 		info->pd_finish_time =
5770Sstevel@tonic-gate 		    (asinfo.as_fh * 60 + asinfo.as_fm) % DAYS_TO_MINS;
5780Sstevel@tonic-gate 		info->pd_autoresume =
5790Sstevel@tonic-gate 		    (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0;
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 	autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown)
5825295Srandyf 	    ? 1 : 0;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate #ifdef DEBUG
5850Sstevel@tonic-gate 	(void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, "
5865295Srandyf 	    "pd_autoresume = %d\n",
5875295Srandyf 	    autoshutdown_en, asinfo.as_idle, info->pd_autoresume);
5885295Srandyf 
5890Sstevel@tonic-gate 	(void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n",
5905295Srandyf 	    info->pd_start_time, info->pd_finish_time);
5910Sstevel@tonic-gate #endif
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	got_sighup = 1;
5940Sstevel@tonic-gate 	now = last_resume = time(NULL);
5950Sstevel@tonic-gate 	hr_now = gethrtime();
5960Sstevel@tonic-gate 	check_idleness(&now, &hr_now);
5970Sstevel@tonic-gate 	check_shutdown(&now, &hr_now);
5980Sstevel@tonic-gate 	set_alarm(now);
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate static void
check_shutdown(time_t * now,hrtime_t * hr_now)6020Sstevel@tonic-gate check_shutdown(time_t *now, hrtime_t *hr_now)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate 	int		tod_fd = -1;
6050Sstevel@tonic-gate 	int		kbd, mouse, system, least_idle, idlecheck_time;
6060Sstevel@tonic-gate 	int		next_time;
6070Sstevel@tonic-gate 	int		s, f;
6080Sstevel@tonic-gate 	struct tm	tmp_time;
6090Sstevel@tonic-gate 	time_t		start_of_day, time_since_last_resume;
6100Sstevel@tonic-gate 	time_t		wakeup_time;
6110Sstevel@tonic-gate 	extern long	conskbd_idle_time(void);
6120Sstevel@tonic-gate 	extern long	consms_idle_time(void);
6130Sstevel@tonic-gate 	static int	warned_kbd, warned_ms; /* print error msg one time */
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (!autoshutdown_en) {
6160Sstevel@tonic-gate 		shutdown_time = 0;
6170Sstevel@tonic-gate 		return;
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	(void) localtime_r(now, &tmp_time);
6210Sstevel@tonic-gate 	tmp_time.tm_sec = 0;
6220Sstevel@tonic-gate 	tmp_time.tm_min = 0;
6230Sstevel@tonic-gate 	tmp_time.tm_hour = 0;
6240Sstevel@tonic-gate 	start_of_day = mktime(&tmp_time);
6250Sstevel@tonic-gate 	s = start_of_day + info->pd_start_time * 60;
6260Sstevel@tonic-gate 	f = start_of_day + info->pd_finish_time * 60;
6270Sstevel@tonic-gate 	if ((s < f && *now >= s && *now < f) ||
6280Sstevel@tonic-gate 	    (s >= f && (*now < f || *now >= s))) {
6290Sstevel@tonic-gate 		if ((mouse = (int)consms_idle_time()) < 0) {
6300Sstevel@tonic-gate 			if (! warned_ms) {
6310Sstevel@tonic-gate 				warned_ms = 1;
6320Sstevel@tonic-gate 				logerror("powerd: failed to get "
6330Sstevel@tonic-gate 				    "idle time for console mouse");
6340Sstevel@tonic-gate 			}
6350Sstevel@tonic-gate 			return;
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 		if ((kbd = (int)conskbd_idle_time()) < 0) {
6380Sstevel@tonic-gate 			if (! warned_kbd) {
6390Sstevel@tonic-gate 				warned_kbd = 1;
6400Sstevel@tonic-gate 				logerror("powerd: failed to get "
6410Sstevel@tonic-gate 				    "idle time for console keyboard");
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 			return;
6440Sstevel@tonic-gate 		}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 		system = last_system_activity(hr_now);
6470Sstevel@tonic-gate 		/* who is the last to go idle */
6480Sstevel@tonic-gate 		least_idle = MIN(system, MIN(kbd, mouse));
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/*
6510Sstevel@tonic-gate 		 * Calculate time_since_last_resume and the next_time
6520Sstevel@tonic-gate 		 * to auto suspend.
6530Sstevel@tonic-gate 		 */
6540Sstevel@tonic-gate 		start_calc = 1;
6550Sstevel@tonic-gate 		time_since_last_resume = time(NULL) - last_resume;
6560Sstevel@tonic-gate 		next_time = info->pd_idle_time * 60 -
6575295Srandyf 		    MIN(least_idle, time_since_last_resume);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate #ifdef DEBUG
6605295Srandyf 		fprintf(stderr, " check_shutdown: next_time=%d\n", next_time);
6610Sstevel@tonic-gate #endif
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		/*
6640Sstevel@tonic-gate 		 * If we have get the SIGTHAW signal at this point - our
6650Sstevel@tonic-gate 		 * calculation of time_since_last_resume is wrong  so
6660Sstevel@tonic-gate 		 * - we need to recalculate.
6670Sstevel@tonic-gate 		 */
6680Sstevel@tonic-gate 		while (start_calc == 0) {
6690Sstevel@tonic-gate 			/* need to redo calculation */
6700Sstevel@tonic-gate 			start_calc = 1;
6710Sstevel@tonic-gate 			time_since_last_resume = time(NULL) - last_resume;
6720Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
6735295Srandyf 			    MIN(least_idle, time_since_last_resume);
6740Sstevel@tonic-gate 		}
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		/*
6770Sstevel@tonic-gate 		 * Only when everything else is idle, run the user's idlecheck
6780Sstevel@tonic-gate 		 * script.
6790Sstevel@tonic-gate 		 */
6800Sstevel@tonic-gate 		if (next_time <= 0 && do_idlecheck) {
6810Sstevel@tonic-gate 			got_sighup = 0;
6820Sstevel@tonic-gate 			idlecheck_time = run_idlecheck();
6830Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
6845295Srandyf 			    MIN(idlecheck_time, MIN(least_idle,
6855295Srandyf 			    time_since_last_resume));
6860Sstevel@tonic-gate 			/*
6870Sstevel@tonic-gate 			 * If we have caught SIGTHAW or SIGHUP, need to
6880Sstevel@tonic-gate 			 * recalculate.
6890Sstevel@tonic-gate 			 */
6900Sstevel@tonic-gate 			while (start_calc == 0 || got_sighup == 1) {
6910Sstevel@tonic-gate 				start_calc = 1;
6920Sstevel@tonic-gate 				got_sighup = 0;
6930Sstevel@tonic-gate 				idlecheck_time = run_idlecheck();
6940Sstevel@tonic-gate 				time_since_last_resume = time(NULL) -
6955295Srandyf 				    last_resume;
6960Sstevel@tonic-gate 				next_time = info->pd_idle_time * 60 -
6975295Srandyf 				    MIN(idlecheck_time, MIN(least_idle,
6985295Srandyf 				    time_since_last_resume));
6990Sstevel@tonic-gate 			}
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		if (next_time <= 0) {
7030Sstevel@tonic-gate 			if (is_ok2shutdown(now)) {
7040Sstevel@tonic-gate 				/*
7050Sstevel@tonic-gate 				 * Setup the autowakeup alarm.  Clear it
7060Sstevel@tonic-gate 				 * right after poweroff, just in case if
7070Sstevel@tonic-gate 				 * shutdown doesn't go through.
7080Sstevel@tonic-gate 				 */
7090Sstevel@tonic-gate 				if (info->pd_autoresume)
7100Sstevel@tonic-gate 					tod_fd = open(TOD, O_RDWR);
7110Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
7120Sstevel@tonic-gate 					wakeup_time = (*now < f) ? f :
7135295Srandyf 					    (f + DAYS_TO_SECS);
7140Sstevel@tonic-gate 					/*
7150Sstevel@tonic-gate 					 * A software fix for hardware
7160Sstevel@tonic-gate 					 * bug 1217415.
7170Sstevel@tonic-gate 					 */
7180Sstevel@tonic-gate 					if ((wakeup_time - *now) < 180) {
7190Sstevel@tonic-gate 						logerror(
7200Sstevel@tonic-gate 		"Since autowakeup time is less than 3 minutes away, "
7210Sstevel@tonic-gate 		"autoshutdown will not occur.");
7220Sstevel@tonic-gate 						shutdown_time = *now + 180;
723*11053SSurya.Prakki@Sun.COM 						(void) close(tod_fd);
7240Sstevel@tonic-gate 						return;
7250Sstevel@tonic-gate 					}
7260Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_SET_ALARM,
7275295Srandyf 					    &wakeup_time) == -1) {
7285295Srandyf 						logerror("Unable to program TOD"
7295295Srandyf 						    " alarm for autowakeup.");
730*11053SSurya.Prakki@Sun.COM 						(void) close(tod_fd);
7310Sstevel@tonic-gate 						return;
7320Sstevel@tonic-gate 					}
7330Sstevel@tonic-gate 				}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 				(void) poweroff("Autoshutdown",
7360Sstevel@tonic-gate 				    autoshutdown_cmd);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
7390Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_CLEAR_ALARM,
7405295Srandyf 					    NULL) == -1)
7410Sstevel@tonic-gate 						logerror("Unable to clear "
7420Sstevel@tonic-gate 						    "alarm in TOD device.");
743*11053SSurya.Prakki@Sun.COM 					(void) close(tod_fd);
7440Sstevel@tonic-gate 				}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 				(void) time(now);
7470Sstevel@tonic-gate 				/* wait at least 5 mins */
7480Sstevel@tonic-gate 				shutdown_time = *now +
7495295Srandyf 				    ((info->pd_idle_time * 60) > 300 ?
7505295Srandyf 				    (info->pd_idle_time * 60) : 300);
7510Sstevel@tonic-gate 			} else {
7520Sstevel@tonic-gate 				/* wait 5 mins */
7530Sstevel@tonic-gate 				shutdown_time = *now + 300;
7540Sstevel@tonic-gate 			}
7550Sstevel@tonic-gate 		} else
7560Sstevel@tonic-gate 			shutdown_time = *now + next_time;
7570Sstevel@tonic-gate 	} else if (s < f && *now >= f) {
7580Sstevel@tonic-gate 		shutdown_time = s + DAYS_TO_SECS;
7590Sstevel@tonic-gate 	} else
7600Sstevel@tonic-gate 		shutdown_time = s;
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate static int
is_ok2shutdown(time_t * now)7640Sstevel@tonic-gate is_ok2shutdown(time_t *now)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	int	prom_fd = -1;
7670Sstevel@tonic-gate 	char	power_cycles_st[LLEN];
7680Sstevel@tonic-gate 	char	power_cycle_limit_st[LLEN];
7690Sstevel@tonic-gate 	char	system_board_date_st[LLEN];
7700Sstevel@tonic-gate 	int	power_cycles, power_cycle_limit, free_cycles, scaled_cycles;
7710Sstevel@tonic-gate 	time_t	life_began, life_passed;
7720Sstevel@tonic-gate 	int	no_power_cycles = 0;
7730Sstevel@tonic-gate 	int	no_system_board_date = 0;
7740Sstevel@tonic-gate 	int	ret = 1;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/* CONSTCOND */
7770Sstevel@tonic-gate 	while (1) {
7780Sstevel@tonic-gate 		if ((prom_fd = open(PROM, O_RDWR)) == -1 &&
7795295Srandyf 		    (errno == EAGAIN))
7805295Srandyf 			continue;
7810Sstevel@tonic-gate 		break;
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	/*
7850Sstevel@tonic-gate 	 * when #power-cycles property does not exist
7860Sstevel@tonic-gate 	 * power cycles are unlimited.
7870Sstevel@tonic-gate 	 */
7880Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "#power-cycles",
7890Sstevel@tonic-gate 	    power_cycles_st, sizeof (power_cycles_st)) == 0)
7900Sstevel@tonic-gate 		goto ckdone;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (get_prom(prom_fd, root, "power-cycle-limit",
7930Sstevel@tonic-gate 	    power_cycle_limit_st, sizeof (power_cycle_limit_st)) == 0) {
7940Sstevel@tonic-gate 		power_cycle_limit = DEFAULT_POWER_CYCLE_LIMIT;
7950Sstevel@tonic-gate 	} else {
7960Sstevel@tonic-gate 		power_cycle_limit = atoi(power_cycle_limit_st);
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	/*
8000Sstevel@tonic-gate 	 * Allow 10% of power_cycle_limit as free cycles.
8010Sstevel@tonic-gate 	 */
8023028Smh27603 	free_cycles = power_cycle_limit / 10;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	power_cycles = atoi(power_cycles_st);
8050Sstevel@tonic-gate 	if (power_cycles < 0)
8060Sstevel@tonic-gate 		no_power_cycles++;
8070Sstevel@tonic-gate 	else if (power_cycles <= free_cycles)
8080Sstevel@tonic-gate 		goto ckdone;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if (no_power_cycles && log_power_cycles_error == 0) {
8110Sstevel@tonic-gate 		logerror("Invalid PROM property \"#power-cycles\" was found.");
8120Sstevel@tonic-gate 		log_power_cycles_error++;
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "system-board-date",
8160Sstevel@tonic-gate 	    system_board_date_st, sizeof (system_board_date_st)) == 0) {
8170Sstevel@tonic-gate 		no_system_board_date++;
8180Sstevel@tonic-gate 	} else {
8190Sstevel@tonic-gate 		life_began = strtol(system_board_date_st, (char **)NULL, 16);
8200Sstevel@tonic-gate 		if (life_began > *now) {
8210Sstevel@tonic-gate 			no_system_board_date++;
8220Sstevel@tonic-gate 		}
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 	if (no_system_board_date) {
8250Sstevel@tonic-gate 		if (log_system_board_date_error == 0) {
8260Sstevel@tonic-gate 			logerror("No or invalid PROM property "
8270Sstevel@tonic-gate 			    "\"system-board-date\" was found.");
8280Sstevel@tonic-gate 			log_system_board_date_error++;
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		life_began = DEFAULT_SYSTEM_BOARD_DATE;
8310Sstevel@tonic-gate 	}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	life_passed = *now - life_began;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * Since we don't keep the date that last free_cycle is ended, we
8370Sstevel@tonic-gate 	 * need to spread (power_cycle_limit - free_cycles) over the entire
8380Sstevel@tonic-gate 	 * 7-year life span instead of (lifetime - date free_cycles ended).
8390Sstevel@tonic-gate 	 */
8403028Smh27603 	scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) *
8415295Srandyf 	    (power_cycle_limit - free_cycles));
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	if (no_power_cycles)
8440Sstevel@tonic-gate 		goto ckdone;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate #ifdef DEBUG
8470Sstevel@tonic-gate 	(void) fprintf(stderr, "Actual power_cycles = %d\t"
8485295Srandyf 	    "Scaled power_cycles = %d\n", power_cycles, scaled_cycles);
8490Sstevel@tonic-gate #endif
8500Sstevel@tonic-gate 	if (power_cycles > scaled_cycles) {
8510Sstevel@tonic-gate 		if (log_no_autoshutdown_warning == 0) {
8520Sstevel@tonic-gate 			logerror("Automatic shutdown has been temporarily "
8530Sstevel@tonic-gate 			    "suspended in order to preserve the reliability "
8540Sstevel@tonic-gate 			    "of this system.");
8550Sstevel@tonic-gate 			log_no_autoshutdown_warning++;
8560Sstevel@tonic-gate 		}
8570Sstevel@tonic-gate 		ret = 0;
8580Sstevel@tonic-gate 		goto ckdone;
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate ckdone:
8620Sstevel@tonic-gate 	if (prom_fd != -1)
863*11053SSurya.Prakki@Sun.COM 		(void) close(prom_fd);
8640Sstevel@tonic-gate 	return (ret);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate static void
check_idleness(time_t * now,hrtime_t * hr_now)8680Sstevel@tonic-gate check_idleness(time_t *now, hrtime_t *hr_now)
8690Sstevel@tonic-gate {
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	/*
8720Sstevel@tonic-gate 	 * Check idleness only when autoshutdown is enabled.
8730Sstevel@tonic-gate 	 */
8740Sstevel@tonic-gate 	if (!autoshutdown_en) {
8750Sstevel@tonic-gate 		checkidle_time = 0;
8760Sstevel@tonic-gate 		return;
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	info->pd_ttychars_idle = check_tty(hr_now, asinfo.ttychars_thold);
8800Sstevel@tonic-gate 	info->pd_loadaverage_idle =
8810Sstevel@tonic-gate 	    check_load_ave(hr_now, asinfo.loadaverage_thold);
8820Sstevel@tonic-gate 	info->pd_diskreads_idle = check_disks(hr_now, asinfo.diskreads_thold);
8830Sstevel@tonic-gate 	info->pd_nfsreqs_idle = check_nfs(hr_now, asinfo.nfsreqs_thold);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate #ifdef DEBUG
8860Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle ttychars for %d secs.\n",
8875295Srandyf 	    info->pd_ttychars_idle);
8880Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle loadaverage for %d secs.\n",
8895295Srandyf 	    info->pd_loadaverage_idle);
8900Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle diskreads for %d secs.\n",
8915295Srandyf 	    info->pd_diskreads_idle);
8920Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle nfsreqs for %d secs.\n",
8935295Srandyf 	    info->pd_nfsreqs_idle);
8940Sstevel@tonic-gate #endif
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	checkidle_time = *now + IDLECHK_INTERVAL;
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate static int
last_system_activity(hrtime_t * hr_now)9000Sstevel@tonic-gate last_system_activity(hrtime_t *hr_now)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	int	act_idle, latest;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	latest = info->pd_idle_time * 60;
9050Sstevel@tonic-gate 	act_idle = last_tty_activity(hr_now, asinfo.ttychars_thold);
9060Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
9070Sstevel@tonic-gate 	act_idle = last_load_ave_activity(hr_now);
9080Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
9090Sstevel@tonic-gate 	act_idle = last_disk_activity(hr_now, asinfo.diskreads_thold);
9100Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
9110Sstevel@tonic-gate 	act_idle = last_nfs_activity(hr_now, asinfo.nfsreqs_thold);
9120Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	return (latest);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate static int
run_idlecheck()9180Sstevel@tonic-gate run_idlecheck()
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	char		pm_variable[LLEN];
9210Sstevel@tonic-gate 	char		*cp;
9220Sstevel@tonic-gate 	int		status;
9230Sstevel@tonic-gate 	pid_t		child;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/*
9260Sstevel@tonic-gate 	 * Reap any child process which has been left over.
9270Sstevel@tonic-gate 	 */
9285295Srandyf 	while (waitpid((pid_t)-1, &status, WNOHANG) > 0)
9295295Srandyf 		;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	/*
9320Sstevel@tonic-gate 	 * Execute the user's idlecheck script and set variable PM_IDLETIME.
9330Sstevel@tonic-gate 	 * Returned exit value is the idle time in minutes.
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
9360Sstevel@tonic-gate 		(void) sprintf(pm_variable, "PM_IDLETIME=%d",
9375295Srandyf 		    info->pd_idle_time);
9380Sstevel@tonic-gate 		(void) putenv(pm_variable);
9390Sstevel@tonic-gate 		cp = strrchr(asinfo.idlecheck_path, '/');
9400Sstevel@tonic-gate 		if (cp == NULL)
9410Sstevel@tonic-gate 			cp = asinfo.idlecheck_path;
9420Sstevel@tonic-gate 		else
9430Sstevel@tonic-gate 			cp++;
9440Sstevel@tonic-gate 		(void) execl(asinfo.idlecheck_path, cp, NULL);
9450Sstevel@tonic-gate 		exit(-1);
9460Sstevel@tonic-gate 	} else if (child == -1) {
9470Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Wait until the idlecheck program completes.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	if (waitpid(child, &status, 0) != child) {
9540Sstevel@tonic-gate 		/*
9550Sstevel@tonic-gate 		 * We get here if the calling process gets a signal.
9560Sstevel@tonic-gate 		 */
9570Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	if (WEXITSTATUS(status) < 0) {
9610Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
9620Sstevel@tonic-gate 	} else {
9630Sstevel@tonic-gate 		return (WEXITSTATUS(status) * 60);
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate static void
set_alarm(time_t now)9680Sstevel@tonic-gate set_alarm(time_t now)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	time_t	itime, stime, next_time, max_time;
9710Sstevel@tonic-gate 	int	next_alarm;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	max_time = MAX(checkidle_time, shutdown_time);
9740Sstevel@tonic-gate 	if (max_time == 0) {
9750Sstevel@tonic-gate 		(void) alarm(0);
9760Sstevel@tonic-gate 		return;
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 	itime = (checkidle_time == 0) ? max_time : checkidle_time;
9790Sstevel@tonic-gate 	stime = (shutdown_time == 0) ? max_time : shutdown_time;
9800Sstevel@tonic-gate 	next_time = MIN(itime, stime);
9810Sstevel@tonic-gate 	next_alarm = (next_time <= now) ? 1 : (next_time - now);
9820Sstevel@tonic-gate 	(void) alarm(next_alarm);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate #ifdef DEBUG
9850Sstevel@tonic-gate 	(void) fprintf(stderr, "Currently @ %s", ctime(&now));
9860Sstevel@tonic-gate 	(void) fprintf(stderr, "Checkidle in %d secs\n", checkidle_time - now);
9870Sstevel@tonic-gate 	(void) fprintf(stderr, "Shutdown  in %d secs\n", shutdown_time - now);
9880Sstevel@tonic-gate 	(void) fprintf(stderr, "Next alarm goes off in %d secs\n", next_alarm);
9890Sstevel@tonic-gate 	(void) fprintf(stderr, "************************************\n");
9900Sstevel@tonic-gate #endif
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate static int
poweroff(const char * msg,char ** cmd_argv)9943028Smh27603 poweroff(const char *msg, char **cmd_argv)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	struct stat	statbuf;
9970Sstevel@tonic-gate 	pid_t		pid, child;
9980Sstevel@tonic-gate 	struct passwd	*pwd;
9990Sstevel@tonic-gate 	char		*home, *user;
10000Sstevel@tonic-gate 	char		ehome[] = "HOME=";
10010Sstevel@tonic-gate 	char		euser[] = "LOGNAME=";
10020Sstevel@tonic-gate 	int		status;
10030Sstevel@tonic-gate 	char		**ca;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	if (mutex_trylock(&poweroff_mutex) != 0)
10060Sstevel@tonic-gate 		return (0);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	if (stat("/dev/console", &statbuf) == -1 ||
10090Sstevel@tonic-gate 	    (pwd = getpwuid(statbuf.st_uid)) == NULL) {
1010*11053SSurya.Prakki@Sun.COM 		(void) mutex_unlock(&poweroff_mutex);
10110Sstevel@tonic-gate 		return (1);
10120Sstevel@tonic-gate 	}
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	if (msg)
10150Sstevel@tonic-gate 		syslog(LOG_NOTICE, msg);
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if (*cmd_argv == NULL) {
10180Sstevel@tonic-gate 		logerror("No command to run.");
1019*11053SSurya.Prakki@Sun.COM 		(void) mutex_unlock(&poweroff_mutex);
10200Sstevel@tonic-gate 		return (1);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	home = malloc(strlen(pwd->pw_dir) + sizeof (ehome));
10240Sstevel@tonic-gate 	user = malloc(strlen(pwd->pw_name) + sizeof (euser));
10250Sstevel@tonic-gate 	if (home == NULL || user == NULL) {
10260Sstevel@tonic-gate 		free(home);
10270Sstevel@tonic-gate 		free(user);
10280Sstevel@tonic-gate 		logerror("No memory.");
1029*11053SSurya.Prakki@Sun.COM 		(void) mutex_unlock(&poweroff_mutex);
10300Sstevel@tonic-gate 		return (1);
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 	(void) strcpy(home, ehome);
10330Sstevel@tonic-gate 	(void) strcat(home, pwd->pw_dir);
10340Sstevel@tonic-gate 	(void) strcpy(user, euser);
10350Sstevel@tonic-gate 	(void) strcat(user, pwd->pw_name);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	/*
10380Sstevel@tonic-gate 	 * Need to simulate the user enviroment, minimaly set HOME, and USER.
10390Sstevel@tonic-gate 	 */
10400Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
10410Sstevel@tonic-gate 		(void) putenv(home);
10420Sstevel@tonic-gate 		(void) putenv(user);
10430Sstevel@tonic-gate 		(void) setgid(pwd->pw_gid);
10440Sstevel@tonic-gate 		(void) setuid(pwd->pw_uid);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 		/*
10470Sstevel@tonic-gate 		 * check for shutdown flag and set environment
10480Sstevel@tonic-gate 		 */
10490Sstevel@tonic-gate 		for (ca = cmd_argv; *ca; ca++) {
10500Sstevel@tonic-gate 			if (strcmp("-h", *ca) == 0) {
10510Sstevel@tonic-gate 				(void) putenv("SYSSUSPENDDODEFAULT=");
10520Sstevel@tonic-gate 				break;
10530Sstevel@tonic-gate 			}
10540Sstevel@tonic-gate 		}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 		(void) execv(cmd_argv[0], cmd_argv);
10570Sstevel@tonic-gate 		exit(EXIT_FAILURE);
10580Sstevel@tonic-gate 	} else {
10590Sstevel@tonic-gate 		free(home);
10600Sstevel@tonic-gate 		free(user);
10610Sstevel@tonic-gate 		if (child == -1) {
1062*11053SSurya.Prakki@Sun.COM 			(void) mutex_unlock(&poweroff_mutex);
10630Sstevel@tonic-gate 			return (1);
10640Sstevel@tonic-gate 		}
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate 	pid = 0;
10670Sstevel@tonic-gate 	while (pid != child)
10680Sstevel@tonic-gate 		pid = wait(&status);
10690Sstevel@tonic-gate 	if (WEXITSTATUS(status)) {
10700Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "Failed to exec \"%s\".", cmd_argv[0]);
1071*11053SSurya.Prakki@Sun.COM 		(void) mutex_unlock(&poweroff_mutex);
10720Sstevel@tonic-gate 		return (1);
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
1075*11053SSurya.Prakki@Sun.COM 	(void) mutex_unlock(&poweroff_mutex);
10760Sstevel@tonic-gate 	return (0);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate #define	PBUFSIZE	256
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate  * Gets the value of a prom property at either root or options node.  It
10830Sstevel@tonic-gate  * returns 1 if it is successful, otherwise it returns 0 .
10840Sstevel@tonic-gate  */
10850Sstevel@tonic-gate static int
get_prom(int prom_fd,prom_node_t node_name,char * property_name,char * property_value,size_t len)10860Sstevel@tonic-gate get_prom(int prom_fd, prom_node_t node_name,
10870Sstevel@tonic-gate 	char *property_name, char *property_value, size_t len)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	union {
10900Sstevel@tonic-gate 		char buf[PBUFSIZE + sizeof (uint_t)];
10910Sstevel@tonic-gate 		struct openpromio opp;
10920Sstevel@tonic-gate 	} oppbuf;
10930Sstevel@tonic-gate 	register struct openpromio *opp = &(oppbuf.opp);
10940Sstevel@tonic-gate 	int	got_it = 0;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	if (prom_fd == -1) {
10970Sstevel@tonic-gate 		return (0);
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	switch (node_name) {
11010Sstevel@tonic-gate 	case root:
11020Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
11030Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
11040Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNEXT, opp) < 0) {
11050Sstevel@tonic-gate 			return (0);
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		/*
11090Sstevel@tonic-gate 		 * Passing null string will give us the first property.
11100Sstevel@tonic-gate 		 */
11110Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
11120Sstevel@tonic-gate 		do {
11130Sstevel@tonic-gate 			opp->oprom_size = PBUFSIZE;
11140Sstevel@tonic-gate 			if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) {
11150Sstevel@tonic-gate 				return (0);
11160Sstevel@tonic-gate 			}
11170Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, property_name) == 0) {
11180Sstevel@tonic-gate 				got_it++;
11190Sstevel@tonic-gate 				break;
11200Sstevel@tonic-gate 			}
11210Sstevel@tonic-gate 		} while (opp->oprom_size > 0);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		if (!got_it) {
11240Sstevel@tonic-gate 			return (0);
11250Sstevel@tonic-gate 		}
11260Sstevel@tonic-gate 		if (got_it && property_value == NULL) {
11270Sstevel@tonic-gate 			return (1);
11280Sstevel@tonic-gate 		}
11290Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
11300Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) {
11310Sstevel@tonic-gate 			return (0);
11320Sstevel@tonic-gate 		}
11330Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
11340Sstevel@tonic-gate 			*property_value = '\0';
11350Sstevel@tonic-gate 		} else {
11360Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 		break;
11390Sstevel@tonic-gate 	case options:
11400Sstevel@tonic-gate 		estrcpy(opp->oprom_array, property_name, PBUFSIZE);
11410Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
11420Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
11430Sstevel@tonic-gate 			return (0);
11440Sstevel@tonic-gate 		}
11450Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
11460Sstevel@tonic-gate 			return (0);
11470Sstevel@tonic-gate 		}
11480Sstevel@tonic-gate 		if (property_value != NULL) {
11490Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
11500Sstevel@tonic-gate 		}
11510Sstevel@tonic-gate 		break;
11520Sstevel@tonic-gate 	default:
11530Sstevel@tonic-gate 		logerror("Only root node and options node are supported.\n");
11540Sstevel@tonic-gate 		return (0);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	return (1);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate #define	isspace(ch)	((ch) == ' ' || (ch) == '\t')
11610Sstevel@tonic-gate #define	iseol(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate /*ARGSUSED*/
11640Sstevel@tonic-gate static void
power_button_monitor(void * arg)11650Sstevel@tonic-gate power_button_monitor(void *arg)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	struct pollfd pfd;
11686573Sphitran 	int events, ret;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) {
11710Sstevel@tonic-gate 		logerror("Failed to monitor the power button.");
11720Sstevel@tonic-gate 		thr_exit((void *) 0);
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	pfd.fd = pb_fd;
11760Sstevel@tonic-gate 	pfd.events = POLLIN;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/*CONSTCOND*/
11790Sstevel@tonic-gate 	while (1) {
11800Sstevel@tonic-gate 		if (poll(&pfd, 1, INFTIM) == -1) {
11810Sstevel@tonic-gate 			logerror("Failed to poll for power button events.");
11820Sstevel@tonic-gate 			thr_exit((void *) 0);
11830Sstevel@tonic-gate 		}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 		if (!(pfd.revents & POLLIN))
11860Sstevel@tonic-gate 			continue;
11870Sstevel@tonic-gate 
11886573Sphitran 		/*
11896573Sphitran 		 * Monitor the power button, but only take action if
11906573Sphitran 		 * gnome-power-manager is not running.
11916573Sphitran 		 *
11926573Sphitran 		 * ret greater than 0 means could not find process.
11936573Sphitran 		 */
11949590SPhi.Tran@Sun.COM 		ret = system("/usr/bin/pgrep -fx gnome-power-manager");
11956573Sphitran 
11960Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
11970Sstevel@tonic-gate 			logerror("Failed to get power button events.");
11980Sstevel@tonic-gate 			thr_exit((void *) 0);
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 
12016573Sphitran 		if ((ret > 0) && (events & PB_BUTTON_PRESS) &&
12020Sstevel@tonic-gate 		    (poweroff(NULL, power_button_cmd) != 0)) {
12030Sstevel@tonic-gate 			logerror("Power button is pressed, powering "
12040Sstevel@tonic-gate 			    "down the system!");
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 			/*
12070Sstevel@tonic-gate 			 * Send SIGPWR signal to the init process to
12080Sstevel@tonic-gate 			 * shut down the system.
12090Sstevel@tonic-gate 			 */
12100Sstevel@tonic-gate 			if (kill(1, SIGPWR) == -1)
12110Sstevel@tonic-gate 				(void) uadmin(A_SHUTDOWN, AD_POWEROFF, 0);
12120Sstevel@tonic-gate 		}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		/*
12150Sstevel@tonic-gate 		 * Clear any power button event that has happened
12160Sstevel@tonic-gate 		 * meanwhile we were busy processing the last one.
12170Sstevel@tonic-gate 		 */
12180Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
12190Sstevel@tonic-gate 			logerror("Failed to get power button events.");
12200Sstevel@tonic-gate 			thr_exit((void *) 0);
12210Sstevel@tonic-gate 		}
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate static void
do_attach(void)12260Sstevel@tonic-gate do_attach(void)
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate 	if (read_cpr_config() < 0)
12290Sstevel@tonic-gate 		return;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	/*
12320Sstevel@tonic-gate 	 * If autopm behavior is explicitly enabled for energystar-v2, or
12330Sstevel@tonic-gate 	 * set to default for energystar-v3, create a new thread to attach
12340Sstevel@tonic-gate 	 * all devices.
12350Sstevel@tonic-gate 	 */
12360Sstevel@tonic-gate 	estar_v3_prop = asinfo.is_autopm_default;
12370Sstevel@tonic-gate 	if ((strcmp(asinfo.apm_behavior, "enable") == 0) ||
12380Sstevel@tonic-gate 	    (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) {
12395295Srandyf 		if (powerd_debug)
12405295Srandyf 			logerror("powerd starting device attach thread.");
12410Sstevel@tonic-gate 		if (thr_create(NULL, NULL, attach_devices, NULL,
12420Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
12430Sstevel@tonic-gate 			logerror("Unable to create thread to attach devices.");
12440Sstevel@tonic-gate 		}
12450Sstevel@tonic-gate 	}
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate /*ARGSUSED*/
12490Sstevel@tonic-gate static void *
attach_devices(void * arg)12500Sstevel@tonic-gate attach_devices(void *arg)
12510Sstevel@tonic-gate {
12520Sstevel@tonic-gate 	di_node_t root_node;
12530Sstevel@tonic-gate 
1254*11053SSurya.Prakki@Sun.COM 	(void) sleep(60);	/* let booting finish first */
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) {
12570Sstevel@tonic-gate 		logerror("Failed to attach devices.");
12580Sstevel@tonic-gate 		return (NULL);
12590Sstevel@tonic-gate 	}
12600Sstevel@tonic-gate 	di_fini(root_node);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	/*
12630Sstevel@tonic-gate 	 * Unload all the modules.
12640Sstevel@tonic-gate 	 */
12650Sstevel@tonic-gate 	(void) modctl(MODUNLOAD, 0);
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	return (NULL);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate /*
12720Sstevel@tonic-gate  * Create a file which will contain our pid.  Pmconfig will check this file
12730Sstevel@tonic-gate  * to see if we are running and can use the pid to signal us.  Returns the
12740Sstevel@tonic-gate  * file descriptor if successful, -1 otherwise.
12750Sstevel@tonic-gate  *
12760Sstevel@tonic-gate  * Note: Deal with attempt to launch multiple instances and also with existence
12770Sstevel@tonic-gate  * of an obsolete pid file caused by an earlier abort.
12780Sstevel@tonic-gate  */
12790Sstevel@tonic-gate static int
open_pidfile(char * me)12800Sstevel@tonic-gate open_pidfile(char *me)
12810Sstevel@tonic-gate {
12820Sstevel@tonic-gate 	int fd;
12833028Smh27603 	const char *e1 = "%s: Cannot open pid file for read: ";
12843028Smh27603 	const char *e2 = "%s: Cannot unlink obsolete pid file: ";
128510846SMargot.Miller@Sun.COM 	const char *e3 = "%s: Either another daemon is running or the"
128610846SMargot.Miller@Sun.COM 	    " process is defunct (pid %d). \n";
128710846SMargot.Miller@Sun.COM 	const char *e4 = "%s: Cannot create pid file: ";
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate again:
12900Sstevel@tonic-gate 	if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) {
12910Sstevel@tonic-gate 		if (errno  == EEXIST) {
12920Sstevel@tonic-gate 			FILE *fp;
12930Sstevel@tonic-gate 			pid_t pid;
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 			if ((fp = fopen(pidpath, "r")) == NULL) {
12960Sstevel@tonic-gate 				(void) fprintf(stderr, e1, me);
12970Sstevel@tonic-gate 				perror(NULL);
12980Sstevel@tonic-gate 				return (-1);
12990Sstevel@tonic-gate 			}
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 			/* Read the pid */
13020Sstevel@tonic-gate 			pid = (pid_t)-1;
13030Sstevel@tonic-gate 			(void) fscanf(fp, "%ld", &pid);
13040Sstevel@tonic-gate 			(void) fclose(fp);
13050Sstevel@tonic-gate 			if (pid == -1) {
13060Sstevel@tonic-gate 				if (unlink(pidpath) == -1) {
13070Sstevel@tonic-gate 					(void) fprintf(stderr, e2, me);
13080Sstevel@tonic-gate 					perror(NULL);
13090Sstevel@tonic-gate 					return (-1);
13100Sstevel@tonic-gate 				} else /* try without corrupted file */
13110Sstevel@tonic-gate 					goto again;
13120Sstevel@tonic-gate 			}
13130Sstevel@tonic-gate 
131410846SMargot.Miller@Sun.COM 			/* Is pid for a running process */
131510846SMargot.Miller@Sun.COM 			if (kill(pid, 0) == -1) {
131610846SMargot.Miller@Sun.COM 				if (errno == ESRCH) {
13170Sstevel@tonic-gate 					if (unlink(pidpath) == -1) {
13180Sstevel@tonic-gate 						(void) fprintf(stderr, e2, me);
13190Sstevel@tonic-gate 						perror(NULL);
13200Sstevel@tonic-gate 						return (-1);
13210Sstevel@tonic-gate 					} else	/* try without obsolete file */
13220Sstevel@tonic-gate 						goto again;
13230Sstevel@tonic-gate 				}
132410846SMargot.Miller@Sun.COM 			} else {    /* powerd deamon still running or defunct */
13250Sstevel@tonic-gate 				(void) fprintf(stderr, e3, me, pid);
13260Sstevel@tonic-gate 				return (-1);
13270Sstevel@tonic-gate 			}
132810846SMargot.Miller@Sun.COM 
13290Sstevel@tonic-gate 		} else {	/* create failure not due to existing file */
133010846SMargot.Miller@Sun.COM 			(void) fprintf(stderr, e4, me);
13310Sstevel@tonic-gate 			perror(NULL);
13320Sstevel@tonic-gate 			return (-1);
13330Sstevel@tonic-gate 		}
13340Sstevel@tonic-gate 	}
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	(void) fchown(fd, (uid_t)-1, (gid_t)0);
13370Sstevel@tonic-gate 	return (fd);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate /*
13410Sstevel@tonic-gate  * Write a pid to the pid file.  Report errors to syslog.
13420Sstevel@tonic-gate  *
13430Sstevel@tonic-gate  */
13440Sstevel@tonic-gate static int
write_pidfile(int fd,pid_t pid)13450Sstevel@tonic-gate write_pidfile(int fd, pid_t pid)
13460Sstevel@tonic-gate {
13470Sstevel@tonic-gate 	int	len;
13480Sstevel@tonic-gate 	int	rc = 0;			/* assume success */
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	len = sprintf(scratch, "%ld\n", pid);
13510Sstevel@tonic-gate 	if (write(fd, scratch, len) != len) {
13520Sstevel@tonic-gate 		logerror("Cannot write pid file: %s", strerror(errno));
13530Sstevel@tonic-gate 		rc = -1;
13540Sstevel@tonic-gate 	}
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	return (rc);
13570Sstevel@tonic-gate }
1358