xref: /titanic_51/usr/src/cmd/power/powerd.c (revision c42872d4489d6f0fbccfabe2a62f3c976ee1e5d6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*c42872d4Smh27603  * Common Development and Distribution License (the "License").
6*c42872d4Smh27603  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c42872d4Smh27603  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>			/* Standard */
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <fcntl.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <time.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <pwd.h>
357c478bd9Sstevel@tonic-gate #include <procfs.h>
367c478bd9Sstevel@tonic-gate #include <dirent.h>
377c478bd9Sstevel@tonic-gate #include <thread.h>
387c478bd9Sstevel@tonic-gate #include <limits.h>
397c478bd9Sstevel@tonic-gate #include <sys/todio.h>			/* Time-Of-Day chip */
407c478bd9Sstevel@tonic-gate #include <sys/stat.h>
417c478bd9Sstevel@tonic-gate #include <sys/wait.h>
427c478bd9Sstevel@tonic-gate #include <sys/ipc.h>			/* IPC functions */
437c478bd9Sstevel@tonic-gate #include <signal.h>			/* signal handling */
447c478bd9Sstevel@tonic-gate #include <syslog.h>
457c478bd9Sstevel@tonic-gate #include <unistd.h>
467c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
477c478bd9Sstevel@tonic-gate #include <poll.h>
487c478bd9Sstevel@tonic-gate #include <sys/pm.h>			/* power management driver */
497c478bd9Sstevel@tonic-gate #include <sys/uadmin.h>
507c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>		/* for prom access */
517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>		/* for MIN & MAX macros */
527c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
537c478bd9Sstevel@tonic-gate #include <sys/stropts.h>		/* for INFTIM */
547c478bd9Sstevel@tonic-gate #include <sys/pbio.h>
557c478bd9Sstevel@tonic-gate #include <sys/cpr.h>
567c478bd9Sstevel@tonic-gate #include <stdarg.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include "powerd.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /* External Functions */
617c478bd9Sstevel@tonic-gate extern struct tm *localtime_r(const time_t *, struct tm *);
627c478bd9Sstevel@tonic-gate extern void sysstat_init(void);
637c478bd9Sstevel@tonic-gate extern int check_tty(hrtime_t *, int);
647c478bd9Sstevel@tonic-gate extern int check_disks(hrtime_t *, int);
657c478bd9Sstevel@tonic-gate extern int check_load_ave(hrtime_t *, float);
667c478bd9Sstevel@tonic-gate extern int check_nfs(hrtime_t *, int);
677c478bd9Sstevel@tonic-gate extern int last_disk_activity(hrtime_t *, int);
687c478bd9Sstevel@tonic-gate extern int last_tty_activity(hrtime_t *, int);
697c478bd9Sstevel@tonic-gate extern int last_load_ave_activity(hrtime_t *);
707c478bd9Sstevel@tonic-gate extern int last_nfs_activity(hrtime_t *, int);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	PM		"/dev/pm"
737c478bd9Sstevel@tonic-gate #define	TOD		"/dev/tod"
747c478bd9Sstevel@tonic-gate #define	PROM		"/dev/openprom"
757c478bd9Sstevel@tonic-gate #define	PB		"/dev/power_button"
767c478bd9Sstevel@tonic-gate #define	LOGFILE		"./powerd.log"
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	PBM_THREAD	0
797c478bd9Sstevel@tonic-gate #define	ATTACH_THREAD	1
807c478bd9Sstevel@tonic-gate #define	NUM_THREADS	2
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate #define	CHECK_INTERVAL	5
837c478bd9Sstevel@tonic-gate #define	IDLECHK_INTERVAL	15
847c478bd9Sstevel@tonic-gate #define	MINS_TO_SECS	60
857c478bd9Sstevel@tonic-gate #define	HOURS_TO_SECS	(60 * 60)
867c478bd9Sstevel@tonic-gate #define	DAYS_TO_SECS	(24 * 60 * 60)
877c478bd9Sstevel@tonic-gate #define	HOURS_TO_MINS	60
887c478bd9Sstevel@tonic-gate #define	DAYS_TO_MINS	(24 * 60)
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #define	LIFETIME_SECS			(7 * 365 * DAYS_TO_SECS)
917c478bd9Sstevel@tonic-gate #define	DEFAULT_POWER_CYCLE_LIMIT	10000
927c478bd9Sstevel@tonic-gate #define	DEFAULT_SYSTEM_BOARD_DATE	804582000	/* July 1, 1995 */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #define	LLEN 80
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate typedef	enum {root, options} prom_node_t;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* State Variables */
997c478bd9Sstevel@tonic-gate static struct cprconfig	asinfo;
1007c478bd9Sstevel@tonic-gate static time_t		shutdown_time;	/* Time for next shutdown check */
1017c478bd9Sstevel@tonic-gate static time_t		checkidle_time;	/* Time for next idleness check */
1027c478bd9Sstevel@tonic-gate static time_t		last_resume;
1037c478bd9Sstevel@tonic-gate pwr_info_t		*info;		/* private as config data buffer */
1047c478bd9Sstevel@tonic-gate static int		pb_fd;		/* power button driver */
1057c478bd9Sstevel@tonic-gate static int		broadcast;	/* Enables syslog messages */
1067c478bd9Sstevel@tonic-gate static int		start_calc;
1077c478bd9Sstevel@tonic-gate static int		autoshutdown_en;
1087c478bd9Sstevel@tonic-gate static int		do_idlecheck;
1097c478bd9Sstevel@tonic-gate static int		got_sighup;
1107c478bd9Sstevel@tonic-gate static int		estar_v2_prop;
111*c42872d4Smh27603 #ifdef sparc
1127c478bd9Sstevel@tonic-gate static int		estar_v3_prop;
113*c42872d4Smh27603 #endif
1147c478bd9Sstevel@tonic-gate static int		log_power_cycles_error = 0;
1157c478bd9Sstevel@tonic-gate static int		log_system_board_date_error = 0;
1167c478bd9Sstevel@tonic-gate static int		log_no_autoshutdown_warning = 0;
1177c478bd9Sstevel@tonic-gate static mutex_t		poweroff_mutex;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static char *autoshutdown_cmd[] = {
1207c478bd9Sstevel@tonic-gate 	"/usr/openwin/bin/sys-suspend",
1217c478bd9Sstevel@tonic-gate 	"-n", "-d", ":0", NULL
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static char *power_button_cmd[] = {
1257c478bd9Sstevel@tonic-gate 	"/usr/openwin/bin/sys-suspend",
1267c478bd9Sstevel@tonic-gate 	"-h", "-d", ":0", NULL
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static char pidpath[] = PIDPATH;
1307c478bd9Sstevel@tonic-gate static char scratch[PATH_MAX];
1317c478bd9Sstevel@tonic-gate static char *prog;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /* Local Functions */
1347c478bd9Sstevel@tonic-gate static void alarm_handler(int);
1357c478bd9Sstevel@tonic-gate static void thaw_handler(int);
1367c478bd9Sstevel@tonic-gate static void kill_handler(int);
1377c478bd9Sstevel@tonic-gate static void work_handler(int);
1387c478bd9Sstevel@tonic-gate static void check_shutdown(time_t *, hrtime_t *);
1397c478bd9Sstevel@tonic-gate static void check_idleness(time_t *, hrtime_t *);
1407c478bd9Sstevel@tonic-gate static int last_system_activity(hrtime_t *);
1417c478bd9Sstevel@tonic-gate static int run_idlecheck(void);
1427c478bd9Sstevel@tonic-gate static void set_alarm(time_t);
143*c42872d4Smh27603 static int poweroff(const char *, char **);
1447c478bd9Sstevel@tonic-gate static int is_ok2shutdown(time_t *);
1457c478bd9Sstevel@tonic-gate static int get_prom(int, prom_node_t, char *, char *, size_t);
1467c478bd9Sstevel@tonic-gate static void power_button_monitor(void *);
1477c478bd9Sstevel@tonic-gate static int open_pidfile(char *);
1487c478bd9Sstevel@tonic-gate static int write_pidfile(int, pid_t);
1497c478bd9Sstevel@tonic-gate static int read_cpr_config(void);
1507c478bd9Sstevel@tonic-gate static void system_activity_monitor(void);
1517c478bd9Sstevel@tonic-gate #ifdef sparc
1527c478bd9Sstevel@tonic-gate static void do_attach(void);
1537c478bd9Sstevel@tonic-gate static void *attach_devices(void *);
1547c478bd9Sstevel@tonic-gate #endif
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 
157*c42872d4Smh27603 /* PRINTFLIKE1 */
1587c478bd9Sstevel@tonic-gate static void
159*c42872d4Smh27603 logerror(const char *fmt, ...)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	va_list args;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	va_start(args, fmt);
1647c478bd9Sstevel@tonic-gate 	if (broadcast)
1657c478bd9Sstevel@tonic-gate 		vsyslog(LOG_ERR, fmt, args);
1667c478bd9Sstevel@tonic-gate 	va_end(args);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate static void
1717c478bd9Sstevel@tonic-gate estrcpy(char *dst, char *src, size_t dlen)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	size_t slen;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	slen = strlcpy(dst, src, dlen);
1767c478bd9Sstevel@tonic-gate 	if (slen >= dlen) {
1777c478bd9Sstevel@tonic-gate 		logerror("%s: string too long \"%s ...\"\n"
1787c478bd9Sstevel@tonic-gate 		    "(len %d, max %d)\n", prog, dst, slen, dlen - 1);
1797c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate int
1857c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	pid_t		pid;
1887c478bd9Sstevel@tonic-gate 	int		pm_fd;
1897c478bd9Sstevel@tonic-gate 	struct sigaction act;
1907c478bd9Sstevel@tonic-gate 	sigset_t	sigmask;
1917c478bd9Sstevel@tonic-gate 	int		c;
1927c478bd9Sstevel@tonic-gate 	char		errmsg[PATH_MAX + 64];
1937c478bd9Sstevel@tonic-gate 	int		pid_fd;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	prog = argv[0];
1967c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
1977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: Must be root\n", prog);
1987c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if ((pid_fd = open_pidfile(prog)) ==  -1)
2027c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 * Process options
2067c478bd9Sstevel@tonic-gate 	 */
2077c478bd9Sstevel@tonic-gate 	broadcast = 1;
2087c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "n")) != EOF) {
2097c478bd9Sstevel@tonic-gate 		switch (c) {
2107c478bd9Sstevel@tonic-gate 		case 'n':
2117c478bd9Sstevel@tonic-gate 			broadcast = 0;
2127c478bd9Sstevel@tonic-gate 			break;
2137c478bd9Sstevel@tonic-gate 		case '?':
2147c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "Usage: %s [-n]\n", prog);
2157c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	pm_fd = open(PM, O_RDWR);
2207c478bd9Sstevel@tonic-gate 	if (pm_fd == -1) {
221*c42872d4Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM);
2227c478bd9Sstevel@tonic-gate 		perror(errmsg);
2237c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 	(void) close(pm_fd);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*
2287c478bd9Sstevel@tonic-gate 	 * Initialize mutex lock used to insure only one command to
2297c478bd9Sstevel@tonic-gate 	 * run at a time.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) {
2327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2337c478bd9Sstevel@tonic-gate 			"%s: Unable to initialize mutex lock\n", prog);
2347c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) {
238*c42872d4Smh27603 		(void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog);
2397c478bd9Sstevel@tonic-gate 		perror(errmsg);
2407c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * Daemon is set to go...
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if ((pid = fork()) < 0)
2477c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2487c478bd9Sstevel@tonic-gate 	else if (pid != 0)
2497c478bd9Sstevel@tonic-gate 		exit(EXIT_SUCCESS);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	pid = getpid();
2527c478bd9Sstevel@tonic-gate 	openlog(prog, 0, LOG_DAEMON);
2537c478bd9Sstevel@tonic-gate 	if (write_pidfile(pid_fd, pid) == -1)	/* logs errors on failure */
2547c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2557c478bd9Sstevel@tonic-gate 	(void) close(pid_fd);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Close all the parent's file descriptors (Bug 1225843).
2597c478bd9Sstevel@tonic-gate 	 */
2607c478bd9Sstevel@tonic-gate 	closefrom(0);
2617c478bd9Sstevel@tonic-gate 	(void) setsid();
2627c478bd9Sstevel@tonic-gate 	(void) chdir("/");
2637c478bd9Sstevel@tonic-gate 	(void) umask(0);
2647c478bd9Sstevel@tonic-gate #ifdef DEBUG
2657c478bd9Sstevel@tonic-gate 	/*
2667c478bd9Sstevel@tonic-gate 	 * Connect stdout to the console.
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) {
2697c478bd9Sstevel@tonic-gate 		logerror("Unable to connect to the console.");
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate #endif
2727c478bd9Sstevel@tonic-gate 	info->pd_flags = PD_AC;
2737c478bd9Sstevel@tonic-gate 	info->pd_idle_time = -1;
2747c478bd9Sstevel@tonic-gate 	info->pd_start_time = 0;
2757c478bd9Sstevel@tonic-gate 	info->pd_finish_time = 0;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	/*
2787c478bd9Sstevel@tonic-gate 	 * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
2797c478bd9Sstevel@tonic-gate 	 * any time
2807c478bd9Sstevel@tonic-gate 	 */
2817c478bd9Sstevel@tonic-gate 	act.sa_handler = kill_handler;
2827c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
2837c478bd9Sstevel@tonic-gate 	act.sa_flags = 0;
2847c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &act, NULL);
2857c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGINT, &act, NULL);
2867c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &act, NULL);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	(void) sigfillset(&sigmask);
2897c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGQUIT);
2907c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGINT);
2917c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTERM);
2927c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * If "power_button" device node can be opened, create a new
2967c478bd9Sstevel@tonic-gate 	 * thread to monitor the power button.
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 	if ((pb_fd = open(PB, O_RDONLY)) != -1) {
2997c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, NULL,
3007c478bd9Sstevel@tonic-gate 		    (void *(*)(void *))power_button_monitor, NULL,
3017c478bd9Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
3027c478bd9Sstevel@tonic-gate 			logerror("Unable to monitor system's power button.");
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate #ifdef sparc
3077c478bd9Sstevel@tonic-gate 	do_attach();
3087c478bd9Sstevel@tonic-gate #endif
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Create a new thread to monitor system activity and suspend
3127c478bd9Sstevel@tonic-gate 	 * system if idle.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	if (thr_create(NULL, NULL,
3157c478bd9Sstevel@tonic-gate 	    (void *(*)(void *))system_activity_monitor, NULL,
3167c478bd9Sstevel@tonic-gate 	    THR_DAEMON, NULL) != 0) {
3177c478bd9Sstevel@tonic-gate 		logerror("Unable to create thread to monitor system activity.");
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * Block until we receive an explicit terminate signal
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	(void) sigsuspend(&sigmask);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	return (1);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate static void
3297c478bd9Sstevel@tonic-gate system_activity_monitor(void)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	struct sigaction act;
3327c478bd9Sstevel@tonic-gate 	sigset_t sigmask;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/*
3357c478bd9Sstevel@tonic-gate 	 * Setup for gathering system's statistic.
3367c478bd9Sstevel@tonic-gate 	 */
3377c478bd9Sstevel@tonic-gate 	sysstat_init();
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * In addition to the SIGQUIT, SIGINT and SIGTERM signals already
3417c478bd9Sstevel@tonic-gate 	 * being handled, this thread also needs to handle SIGHUP, SIGALRM
3427c478bd9Sstevel@tonic-gate 	 * and SIGTHAW signals.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
3457c478bd9Sstevel@tonic-gate 	act.sa_flags = 0;
3467c478bd9Sstevel@tonic-gate 	act.sa_handler = alarm_handler;
3477c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &act, NULL);
3487c478bd9Sstevel@tonic-gate 	act.sa_handler = work_handler;
3497c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &act, NULL);
3507c478bd9Sstevel@tonic-gate 	act.sa_handler = thaw_handler;
3517c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTHAW, &act, NULL);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/*
3547c478bd9Sstevel@tonic-gate 	 * Invoke work_handler with a dummy SIGHUP signal to read
3557c478bd9Sstevel@tonic-gate 	 * cpr config file, get autoshutdown properties and schedule
3567c478bd9Sstevel@tonic-gate 	 * an alarm if needed.
3577c478bd9Sstevel@tonic-gate 	 */
3587c478bd9Sstevel@tonic-gate 	work_handler(SIGHUP);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/*
3617c478bd9Sstevel@tonic-gate 	 * Wait for signal to read file
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(0, 0, &sigmask);
3647c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGHUP);
3657c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGALRM);
3667c478bd9Sstevel@tonic-gate 	(void) sigdelset(&sigmask, SIGTHAW);
3677c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
3687c478bd9Sstevel@tonic-gate 	do {
3697c478bd9Sstevel@tonic-gate 		(void) sigsuspend(&sigmask);
3707c478bd9Sstevel@tonic-gate 	} while (errno == EINTR);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate static int
3747c478bd9Sstevel@tonic-gate read_cpr_config(void)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	int	asfd;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	if ((asfd = open(CPR_CONFIG, O_RDONLY)) < 0) {
3797c478bd9Sstevel@tonic-gate 		logerror("Unable to open CPR config file '%s'", CPR_CONFIG);
3807c478bd9Sstevel@tonic-gate 		return (-1);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if (read(asfd, (void *)&asinfo, sizeof (asinfo)) != sizeof (asinfo)) {
3847c478bd9Sstevel@tonic-gate 		logerror("Unable to read CPR config file '%s'", CPR_CONFIG);
3857c478bd9Sstevel@tonic-gate 		close(asfd);
3867c478bd9Sstevel@tonic-gate 		return (-1);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	(void) close(asfd);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	return (0);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3957c478bd9Sstevel@tonic-gate static void
3967c478bd9Sstevel@tonic-gate thaw_handler(int sig)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	start_calc  = 0;
3997c478bd9Sstevel@tonic-gate 	last_resume = time(NULL);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4037c478bd9Sstevel@tonic-gate static void
4047c478bd9Sstevel@tonic-gate kill_handler(int sig)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	int ret_code = EXIT_SUCCESS;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/*
4097c478bd9Sstevel@tonic-gate 	 * Free resources
4107c478bd9Sstevel@tonic-gate 	 */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	free(info);
4137c478bd9Sstevel@tonic-gate 	if (pb_fd != -1) {
4147c478bd9Sstevel@tonic-gate 		(void) close(pb_fd);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&poweroff_mutex);
4177c478bd9Sstevel@tonic-gate 	(void) unlink(pidpath);
4187c478bd9Sstevel@tonic-gate 	closelog();
4197c478bd9Sstevel@tonic-gate 	exit(ret_code);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4237c478bd9Sstevel@tonic-gate static void
4247c478bd9Sstevel@tonic-gate alarm_handler(int sig)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	time_t		now;
4277c478bd9Sstevel@tonic-gate 	hrtime_t	hr_now;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	now = time(NULL);
4307c478bd9Sstevel@tonic-gate 	hr_now = gethrtime();
4317c478bd9Sstevel@tonic-gate 	if (checkidle_time <= now && checkidle_time != 0)
4327c478bd9Sstevel@tonic-gate 		check_idleness(&now, &hr_now);
4337c478bd9Sstevel@tonic-gate 	if (shutdown_time <= now && shutdown_time != 0)
4347c478bd9Sstevel@tonic-gate 		check_shutdown(&now, &hr_now);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	set_alarm(now);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4407c478bd9Sstevel@tonic-gate static void
4417c478bd9Sstevel@tonic-gate work_handler(int sig)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	time_t		now;
4447c478bd9Sstevel@tonic-gate 	hrtime_t	hr_now;
4457c478bd9Sstevel@tonic-gate 	struct stat	stat_buf;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	do_idlecheck = 0;
4487c478bd9Sstevel@tonic-gate 	info->pd_flags = PD_AC;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * Parse the config file for autoshutdown and idleness entries.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (read_cpr_config() < 0)
4547c478bd9Sstevel@tonic-gate 		return;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * Since Oct. 1, 1995, any new system shipped had root
4587c478bd9Sstevel@tonic-gate 	 * property "energystar-v2" defined in its prom.  Systems
4597c478bd9Sstevel@tonic-gate 	 * shipped after July 1, 1999, will have "energystar-v3"
4607c478bd9Sstevel@tonic-gate 	 * property.
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 	estar_v2_prop = asinfo.is_cpr_default;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	info->pd_flags |= asinfo.is_autowakeup_capable;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (strlen(asinfo.idlecheck_path) > 0) {
4677c478bd9Sstevel@tonic-gate 		if (stat(asinfo.idlecheck_path, &stat_buf) != 0) {
4687c478bd9Sstevel@tonic-gate 			logerror("unable to access idlecheck program \"%s\".",
4697c478bd9Sstevel@tonic-gate 			    asinfo.idlecheck_path);
4707c478bd9Sstevel@tonic-gate 		} else if (!(stat_buf.st_mode & S_IXUSR)) {
4717c478bd9Sstevel@tonic-gate 			logerror("idlecheck program \"%s\" is not executable.",
4727c478bd9Sstevel@tonic-gate 			    asinfo.idlecheck_path);
4737c478bd9Sstevel@tonic-gate 		} else {
4747c478bd9Sstevel@tonic-gate 			do_idlecheck = 1;
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (strlen(asinfo.as_behavior) == 0 ||
4797c478bd9Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "noshutdown") == 0 ||
4807c478bd9Sstevel@tonic-gate 	    strcmp(asinfo.as_behavior, "unconfigured") == 0) {
4817c478bd9Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
4827c478bd9Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "default") == 0) {
4837c478bd9Sstevel@tonic-gate 		info->pd_autoshutdown = estar_v2_prop;
4847c478bd9Sstevel@tonic-gate 	} else if (strcmp(asinfo.as_behavior, "shutdown") == 0 ||
4857c478bd9Sstevel@tonic-gate 		strcmp(asinfo.as_behavior, "autowakeup") == 0) {
4867c478bd9Sstevel@tonic-gate 		info->pd_autoshutdown = asinfo.is_cpr_capable;
4877c478bd9Sstevel@tonic-gate 	} else {
4887c478bd9Sstevel@tonic-gate 		logerror("autoshutdown behavior \"%s\" unrecognized.",
4897c478bd9Sstevel@tonic-gate 		    asinfo.as_behavior);
4907c478bd9Sstevel@tonic-gate 		info->pd_autoshutdown = 0;
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (info->pd_autoshutdown) {
4947c478bd9Sstevel@tonic-gate 		info->pd_idle_time = asinfo.as_idle;
4957c478bd9Sstevel@tonic-gate 		info->pd_start_time =
4967c478bd9Sstevel@tonic-gate 		    (asinfo.as_sh * 60 + asinfo.as_sm) % DAYS_TO_MINS;
4977c478bd9Sstevel@tonic-gate 		info->pd_finish_time =
4987c478bd9Sstevel@tonic-gate 		    (asinfo.as_fh * 60 + asinfo.as_fm) % DAYS_TO_MINS;
4997c478bd9Sstevel@tonic-gate 		info->pd_autoresume =
5007c478bd9Sstevel@tonic-gate 		    (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 	autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown)
5037c478bd9Sstevel@tonic-gate 		? 1 : 0;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate #ifdef DEBUG
5067c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, "
5077c478bd9Sstevel@tonic-gate 			"pd_autoresume = %d\n",
5087c478bd9Sstevel@tonic-gate 		autoshutdown_en, asinfo.as_idle, info->pd_autoresume);
5097c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n",
5107c478bd9Sstevel@tonic-gate 		info->pd_start_time, info->pd_finish_time);
5117c478bd9Sstevel@tonic-gate #endif
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	got_sighup = 1;
5147c478bd9Sstevel@tonic-gate 	now = last_resume = time(NULL);
5157c478bd9Sstevel@tonic-gate 	hr_now = gethrtime();
5167c478bd9Sstevel@tonic-gate 	check_idleness(&now, &hr_now);
5177c478bd9Sstevel@tonic-gate 	check_shutdown(&now, &hr_now);
5187c478bd9Sstevel@tonic-gate 	set_alarm(now);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate static void
5227c478bd9Sstevel@tonic-gate check_shutdown(time_t *now, hrtime_t *hr_now)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	int		tod_fd = -1;
5257c478bd9Sstevel@tonic-gate 	int		kbd, mouse, system, least_idle, idlecheck_time;
5267c478bd9Sstevel@tonic-gate 	int		next_time;
5277c478bd9Sstevel@tonic-gate 	int		s, f;
5287c478bd9Sstevel@tonic-gate 	struct tm	tmp_time;
5297c478bd9Sstevel@tonic-gate 	time_t		start_of_day, time_since_last_resume;
5307c478bd9Sstevel@tonic-gate 	time_t		wakeup_time;
5317c478bd9Sstevel@tonic-gate 	extern long	conskbd_idle_time(void);
5327c478bd9Sstevel@tonic-gate 	extern long	consms_idle_time(void);
5337c478bd9Sstevel@tonic-gate 	static int	warned_kbd, warned_ms; /* print error msg one time */
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (!autoshutdown_en) {
5367c478bd9Sstevel@tonic-gate 		shutdown_time = 0;
5377c478bd9Sstevel@tonic-gate 		return;
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	(void) localtime_r(now, &tmp_time);
5417c478bd9Sstevel@tonic-gate 	tmp_time.tm_sec = 0;
5427c478bd9Sstevel@tonic-gate 	tmp_time.tm_min = 0;
5437c478bd9Sstevel@tonic-gate 	tmp_time.tm_hour = 0;
5447c478bd9Sstevel@tonic-gate 	start_of_day = mktime(&tmp_time);
5457c478bd9Sstevel@tonic-gate 	s = start_of_day + info->pd_start_time * 60;
5467c478bd9Sstevel@tonic-gate 	f = start_of_day + info->pd_finish_time * 60;
5477c478bd9Sstevel@tonic-gate 	if ((s < f && *now >= s && *now < f) ||
5487c478bd9Sstevel@tonic-gate 	    (s >= f && (*now < f || *now >= s))) {
5497c478bd9Sstevel@tonic-gate 		if ((mouse = (int)consms_idle_time()) < 0) {
5507c478bd9Sstevel@tonic-gate 			if (! warned_ms) {
5517c478bd9Sstevel@tonic-gate 				warned_ms = 1;
5527c478bd9Sstevel@tonic-gate 				logerror("powerd: failed to get "
5537c478bd9Sstevel@tonic-gate 				    "idle time for console mouse");
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 			return;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 		if ((kbd = (int)conskbd_idle_time()) < 0) {
5587c478bd9Sstevel@tonic-gate 			if (! warned_kbd) {
5597c478bd9Sstevel@tonic-gate 				warned_kbd = 1;
5607c478bd9Sstevel@tonic-gate 				logerror("powerd: failed to get "
5617c478bd9Sstevel@tonic-gate 				    "idle time for console keyboard");
5627c478bd9Sstevel@tonic-gate 			}
5637c478bd9Sstevel@tonic-gate 			return;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		system = last_system_activity(hr_now);
5677c478bd9Sstevel@tonic-gate 		/* who is the last to go idle */
5687c478bd9Sstevel@tonic-gate 		least_idle = MIN(system, MIN(kbd, mouse));
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 		/*
5717c478bd9Sstevel@tonic-gate 		 * Calculate time_since_last_resume and the next_time
5727c478bd9Sstevel@tonic-gate 		 * to auto suspend.
5737c478bd9Sstevel@tonic-gate 		 */
5747c478bd9Sstevel@tonic-gate 		start_calc = 1;
5757c478bd9Sstevel@tonic-gate 		time_since_last_resume = time(NULL) - last_resume;
5767c478bd9Sstevel@tonic-gate 		next_time = info->pd_idle_time * 60 -
5777c478bd9Sstevel@tonic-gate 				MIN(least_idle, time_since_last_resume);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate #ifdef DEBUG
5807c478bd9Sstevel@tonic-gate 		fprintf(stderr, " check_shutdown: next_time=%d\n",
5817c478bd9Sstevel@tonic-gate 			next_time);
5827c478bd9Sstevel@tonic-gate #endif
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		/*
5857c478bd9Sstevel@tonic-gate 		 * If we have get the SIGTHAW signal at this point - our
5867c478bd9Sstevel@tonic-gate 		 * calculation of time_since_last_resume is wrong  so
5877c478bd9Sstevel@tonic-gate 		 * - we need to recalculate.
5887c478bd9Sstevel@tonic-gate 		 */
5897c478bd9Sstevel@tonic-gate 		while (start_calc == 0) {
5907c478bd9Sstevel@tonic-gate 			/* need to redo calculation */
5917c478bd9Sstevel@tonic-gate 			start_calc = 1;
5927c478bd9Sstevel@tonic-gate 			time_since_last_resume = time(NULL) - last_resume;
5937c478bd9Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
5947c478bd9Sstevel@tonic-gate 				MIN(least_idle, time_since_last_resume);
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		/*
5987c478bd9Sstevel@tonic-gate 		 * Only when everything else is idle, run the user's idlecheck
5997c478bd9Sstevel@tonic-gate 		 * script.
6007c478bd9Sstevel@tonic-gate 		 */
6017c478bd9Sstevel@tonic-gate 		if (next_time <= 0 && do_idlecheck) {
6027c478bd9Sstevel@tonic-gate 			got_sighup = 0;
6037c478bd9Sstevel@tonic-gate 			idlecheck_time = run_idlecheck();
6047c478bd9Sstevel@tonic-gate 			next_time = info->pd_idle_time * 60 -
6057c478bd9Sstevel@tonic-gate 				MIN(idlecheck_time, MIN(least_idle,
6067c478bd9Sstevel@tonic-gate 				time_since_last_resume));
6077c478bd9Sstevel@tonic-gate 			/*
6087c478bd9Sstevel@tonic-gate 			 * If we have caught SIGTHAW or SIGHUP, need to
6097c478bd9Sstevel@tonic-gate 			 * recalculate.
6107c478bd9Sstevel@tonic-gate 			 */
6117c478bd9Sstevel@tonic-gate 			while (start_calc == 0 || got_sighup == 1) {
6127c478bd9Sstevel@tonic-gate 				start_calc = 1;
6137c478bd9Sstevel@tonic-gate 				got_sighup = 0;
6147c478bd9Sstevel@tonic-gate 				idlecheck_time = run_idlecheck();
6157c478bd9Sstevel@tonic-gate 				time_since_last_resume = time(NULL) -
6167c478bd9Sstevel@tonic-gate 					last_resume;
6177c478bd9Sstevel@tonic-gate 				next_time = info->pd_idle_time * 60 -
6187c478bd9Sstevel@tonic-gate 					MIN(idlecheck_time, MIN(least_idle,
6197c478bd9Sstevel@tonic-gate 					time_since_last_resume));
6207c478bd9Sstevel@tonic-gate 			}
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		if (next_time <= 0) {
6247c478bd9Sstevel@tonic-gate 			if (is_ok2shutdown(now)) {
6257c478bd9Sstevel@tonic-gate 				/*
6267c478bd9Sstevel@tonic-gate 				 * Setup the autowakeup alarm.  Clear it
6277c478bd9Sstevel@tonic-gate 				 * right after poweroff, just in case if
6287c478bd9Sstevel@tonic-gate 				 * shutdown doesn't go through.
6297c478bd9Sstevel@tonic-gate 				 */
6307c478bd9Sstevel@tonic-gate 				if (info->pd_autoresume)
6317c478bd9Sstevel@tonic-gate 					tod_fd = open(TOD, O_RDWR);
6327c478bd9Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
6337c478bd9Sstevel@tonic-gate 					wakeup_time = (*now < f) ? f :
6347c478bd9Sstevel@tonic-gate 							(f + DAYS_TO_SECS);
6357c478bd9Sstevel@tonic-gate 					/*
6367c478bd9Sstevel@tonic-gate 					 * A software fix for hardware
6377c478bd9Sstevel@tonic-gate 					 * bug 1217415.
6387c478bd9Sstevel@tonic-gate 					 */
6397c478bd9Sstevel@tonic-gate 					if ((wakeup_time - *now) < 180) {
6407c478bd9Sstevel@tonic-gate 						logerror(
6417c478bd9Sstevel@tonic-gate 		"Since autowakeup time is less than 3 minutes away, "
6427c478bd9Sstevel@tonic-gate 		"autoshutdown will not occur.");
6437c478bd9Sstevel@tonic-gate 						shutdown_time = *now + 180;
6447c478bd9Sstevel@tonic-gate 						close(tod_fd);
6457c478bd9Sstevel@tonic-gate 						return;
6467c478bd9Sstevel@tonic-gate 					}
6477c478bd9Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_SET_ALARM,
6487c478bd9Sstevel@tonic-gate 							&wakeup_time) == -1) {
6497c478bd9Sstevel@tonic-gate 						logerror("Unable to program "
6507c478bd9Sstevel@tonic-gate 							"TOD alarm for "
6517c478bd9Sstevel@tonic-gate 							"autowakeup.");
6527c478bd9Sstevel@tonic-gate 						close(tod_fd);
6537c478bd9Sstevel@tonic-gate 						return;
6547c478bd9Sstevel@tonic-gate 					}
6557c478bd9Sstevel@tonic-gate 				}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 				(void) poweroff("Autoshutdown",
6587c478bd9Sstevel@tonic-gate 				    autoshutdown_cmd);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 				if (info->pd_autoresume && tod_fd != -1) {
6617c478bd9Sstevel@tonic-gate 					if (ioctl(tod_fd, TOD_CLEAR_ALARM,
6627c478bd9Sstevel@tonic-gate 							NULL) == -1)
6637c478bd9Sstevel@tonic-gate 						logerror("Unable to clear "
6647c478bd9Sstevel@tonic-gate 						    "alarm in TOD device.");
6657c478bd9Sstevel@tonic-gate 					close(tod_fd);
6667c478bd9Sstevel@tonic-gate 				}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 				(void) time(now);
6697c478bd9Sstevel@tonic-gate 				/* wait at least 5 mins */
6707c478bd9Sstevel@tonic-gate 				shutdown_time = *now +
6717c478bd9Sstevel@tonic-gate 					((info->pd_idle_time * 60) > 300 ?
6727c478bd9Sstevel@tonic-gate 					(info->pd_idle_time * 60) : 300);
6737c478bd9Sstevel@tonic-gate 			} else {
6747c478bd9Sstevel@tonic-gate 				/* wait 5 mins */
6757c478bd9Sstevel@tonic-gate 				shutdown_time = *now + 300;
6767c478bd9Sstevel@tonic-gate 			}
6777c478bd9Sstevel@tonic-gate 		} else
6787c478bd9Sstevel@tonic-gate 			shutdown_time = *now + next_time;
6797c478bd9Sstevel@tonic-gate 	} else if (s < f && *now >= f) {
6807c478bd9Sstevel@tonic-gate 		shutdown_time = s + DAYS_TO_SECS;
6817c478bd9Sstevel@tonic-gate 	} else
6827c478bd9Sstevel@tonic-gate 		shutdown_time = s;
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate static int
6867c478bd9Sstevel@tonic-gate is_ok2shutdown(time_t *now)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	int	prom_fd = -1;
6897c478bd9Sstevel@tonic-gate 	char	power_cycles_st[LLEN];
6907c478bd9Sstevel@tonic-gate 	char	power_cycle_limit_st[LLEN];
6917c478bd9Sstevel@tonic-gate 	char	system_board_date_st[LLEN];
6927c478bd9Sstevel@tonic-gate 	int	power_cycles, power_cycle_limit, free_cycles, scaled_cycles;
6937c478bd9Sstevel@tonic-gate 	time_t	life_began, life_passed;
6947c478bd9Sstevel@tonic-gate 	int	no_power_cycles = 0;
6957c478bd9Sstevel@tonic-gate 	int	no_system_board_date = 0;
6967c478bd9Sstevel@tonic-gate 	int	ret = 1;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
6997c478bd9Sstevel@tonic-gate 	while (1) {
7007c478bd9Sstevel@tonic-gate 		if ((prom_fd = open(PROM, O_RDWR)) == -1 &&
7017c478bd9Sstevel@tonic-gate 			(errno == EAGAIN))
7027c478bd9Sstevel@tonic-gate 				continue;
7037c478bd9Sstevel@tonic-gate 		break;
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * when #power-cycles property does not exist
7087c478bd9Sstevel@tonic-gate 	 * power cycles are unlimited.
7097c478bd9Sstevel@tonic-gate 	 */
7107c478bd9Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "#power-cycles",
7117c478bd9Sstevel@tonic-gate 	    power_cycles_st, sizeof (power_cycles_st)) == 0)
7127c478bd9Sstevel@tonic-gate 		goto ckdone;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if (get_prom(prom_fd, root, "power-cycle-limit",
7157c478bd9Sstevel@tonic-gate 	    power_cycle_limit_st, sizeof (power_cycle_limit_st)) == 0) {
7167c478bd9Sstevel@tonic-gate 		power_cycle_limit = DEFAULT_POWER_CYCLE_LIMIT;
7177c478bd9Sstevel@tonic-gate 	} else {
7187c478bd9Sstevel@tonic-gate 		power_cycle_limit = atoi(power_cycle_limit_st);
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	/*
7227c478bd9Sstevel@tonic-gate 	 * Allow 10% of power_cycle_limit as free cycles.
7237c478bd9Sstevel@tonic-gate 	 */
724*c42872d4Smh27603 	free_cycles = power_cycle_limit / 10;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	power_cycles = atoi(power_cycles_st);
7277c478bd9Sstevel@tonic-gate 	if (power_cycles < 0)
7287c478bd9Sstevel@tonic-gate 		no_power_cycles++;
7297c478bd9Sstevel@tonic-gate 	else if (power_cycles <= free_cycles)
7307c478bd9Sstevel@tonic-gate 		goto ckdone;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (no_power_cycles && log_power_cycles_error == 0) {
7337c478bd9Sstevel@tonic-gate 		logerror("Invalid PROM property \"#power-cycles\" was found.");
7347c478bd9Sstevel@tonic-gate 		log_power_cycles_error++;
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	if (get_prom(prom_fd, options, "system-board-date",
7387c478bd9Sstevel@tonic-gate 	    system_board_date_st, sizeof (system_board_date_st)) == 0) {
7397c478bd9Sstevel@tonic-gate 		no_system_board_date++;
7407c478bd9Sstevel@tonic-gate 	} else {
7417c478bd9Sstevel@tonic-gate 		life_began = strtol(system_board_date_st, (char **)NULL, 16);
7427c478bd9Sstevel@tonic-gate 		if (life_began > *now) {
7437c478bd9Sstevel@tonic-gate 			no_system_board_date++;
7447c478bd9Sstevel@tonic-gate 		}
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	if (no_system_board_date) {
7477c478bd9Sstevel@tonic-gate 		if (log_system_board_date_error == 0) {
7487c478bd9Sstevel@tonic-gate 			logerror("No or invalid PROM property "
7497c478bd9Sstevel@tonic-gate 			    "\"system-board-date\" was found.");
7507c478bd9Sstevel@tonic-gate 			log_system_board_date_error++;
7517c478bd9Sstevel@tonic-gate 		}
7527c478bd9Sstevel@tonic-gate 		life_began = DEFAULT_SYSTEM_BOARD_DATE;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	life_passed = *now - life_began;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/*
7587c478bd9Sstevel@tonic-gate 	 * Since we don't keep the date that last free_cycle is ended, we
7597c478bd9Sstevel@tonic-gate 	 * need to spread (power_cycle_limit - free_cycles) over the entire
7607c478bd9Sstevel@tonic-gate 	 * 7-year life span instead of (lifetime - date free_cycles ended).
7617c478bd9Sstevel@tonic-gate 	 */
762*c42872d4Smh27603 	scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) *
763*c42872d4Smh27603 				(power_cycle_limit - free_cycles));
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (no_power_cycles)
7667c478bd9Sstevel@tonic-gate 		goto ckdone;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate #ifdef DEBUG
7697c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Actual power_cycles = %d\t"
7707c478bd9Sstevel@tonic-gate 				"Scaled power_cycles = %d\n",
7717c478bd9Sstevel@tonic-gate 				power_cycles, scaled_cycles);
7727c478bd9Sstevel@tonic-gate #endif
7737c478bd9Sstevel@tonic-gate 	if (power_cycles > scaled_cycles) {
7747c478bd9Sstevel@tonic-gate 		if (log_no_autoshutdown_warning == 0) {
7757c478bd9Sstevel@tonic-gate 			logerror("Automatic shutdown has been temporarily "
7767c478bd9Sstevel@tonic-gate 			    "suspended in order to preserve the reliability "
7777c478bd9Sstevel@tonic-gate 			    "of this system.");
7787c478bd9Sstevel@tonic-gate 			log_no_autoshutdown_warning++;
7797c478bd9Sstevel@tonic-gate 		}
7807c478bd9Sstevel@tonic-gate 		ret = 0;
7817c478bd9Sstevel@tonic-gate 		goto ckdone;
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate ckdone:
7857c478bd9Sstevel@tonic-gate 	if (prom_fd != -1)
7867c478bd9Sstevel@tonic-gate 		close(prom_fd);
7877c478bd9Sstevel@tonic-gate 	return (ret);
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate static void
7917c478bd9Sstevel@tonic-gate check_idleness(time_t *now, hrtime_t *hr_now)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * Check idleness only when autoshutdown is enabled.
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 	if (!autoshutdown_en) {
7987c478bd9Sstevel@tonic-gate 		checkidle_time = 0;
7997c478bd9Sstevel@tonic-gate 		return;
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	info->pd_ttychars_idle = check_tty(hr_now, asinfo.ttychars_thold);
8037c478bd9Sstevel@tonic-gate 	info->pd_loadaverage_idle =
8047c478bd9Sstevel@tonic-gate 	    check_load_ave(hr_now, asinfo.loadaverage_thold);
8057c478bd9Sstevel@tonic-gate 	info->pd_diskreads_idle = check_disks(hr_now, asinfo.diskreads_thold);
8067c478bd9Sstevel@tonic-gate 	info->pd_nfsreqs_idle = check_nfs(hr_now, asinfo.nfsreqs_thold);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate #ifdef DEBUG
8097c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle ttychars for %d secs.\n",
8107c478bd9Sstevel@tonic-gate 			info->pd_ttychars_idle);
8117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle loadaverage for %d secs.\n",
8127c478bd9Sstevel@tonic-gate 			info->pd_loadaverage_idle);
8137c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle diskreads for %d secs.\n",
8147c478bd9Sstevel@tonic-gate 			info->pd_diskreads_idle);
8157c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Idle nfsreqs for %d secs.\n",
8167c478bd9Sstevel@tonic-gate 			info->pd_nfsreqs_idle);
8177c478bd9Sstevel@tonic-gate #endif
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	checkidle_time = *now + IDLECHK_INTERVAL;
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate static int
8237c478bd9Sstevel@tonic-gate last_system_activity(hrtime_t *hr_now)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	int	act_idle, latest;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	latest = info->pd_idle_time * 60;
8287c478bd9Sstevel@tonic-gate 	act_idle = last_tty_activity(hr_now, asinfo.ttychars_thold);
8297c478bd9Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8307c478bd9Sstevel@tonic-gate 	act_idle = last_load_ave_activity(hr_now);
8317c478bd9Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8327c478bd9Sstevel@tonic-gate 	act_idle = last_disk_activity(hr_now, asinfo.diskreads_thold);
8337c478bd9Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8347c478bd9Sstevel@tonic-gate 	act_idle = last_nfs_activity(hr_now, asinfo.nfsreqs_thold);
8357c478bd9Sstevel@tonic-gate 	latest = MIN(latest, act_idle);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	return (latest);
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate static int
8417c478bd9Sstevel@tonic-gate run_idlecheck()
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	char		pm_variable[LLEN];
8447c478bd9Sstevel@tonic-gate 	char		*cp;
8457c478bd9Sstevel@tonic-gate 	int		status;
8467c478bd9Sstevel@tonic-gate 	pid_t		child;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/*
8497c478bd9Sstevel@tonic-gate 	 * Reap any child process which has been left over.
8507c478bd9Sstevel@tonic-gate 	 */
8517c478bd9Sstevel@tonic-gate 	while (waitpid((pid_t)-1, &status, WNOHANG) > 0);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * Execute the user's idlecheck script and set variable PM_IDLETIME.
8557c478bd9Sstevel@tonic-gate 	 * Returned exit value is the idle time in minutes.
8567c478bd9Sstevel@tonic-gate 	 */
8577c478bd9Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
8587c478bd9Sstevel@tonic-gate 		(void) sprintf(pm_variable, "PM_IDLETIME=%d",
8597c478bd9Sstevel@tonic-gate 			info->pd_idle_time);
8607c478bd9Sstevel@tonic-gate 		(void) putenv(pm_variable);
8617c478bd9Sstevel@tonic-gate 		cp = strrchr(asinfo.idlecheck_path, '/');
8627c478bd9Sstevel@tonic-gate 		if (cp == NULL)
8637c478bd9Sstevel@tonic-gate 			cp = asinfo.idlecheck_path;
8647c478bd9Sstevel@tonic-gate 		else
8657c478bd9Sstevel@tonic-gate 			cp++;
8667c478bd9Sstevel@tonic-gate 		(void) execl(asinfo.idlecheck_path, cp, NULL);
8677c478bd9Sstevel@tonic-gate 		exit(-1);
8687c478bd9Sstevel@tonic-gate 	} else if (child == -1) {
8697c478bd9Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/*
8737c478bd9Sstevel@tonic-gate 	 * Wait until the idlecheck program completes.
8747c478bd9Sstevel@tonic-gate 	 */
8757c478bd9Sstevel@tonic-gate 	if (waitpid(child, &status, 0) != child) {
8767c478bd9Sstevel@tonic-gate 		/*
8777c478bd9Sstevel@tonic-gate 		 * We get here if the calling process gets a signal.
8787c478bd9Sstevel@tonic-gate 		 */
8797c478bd9Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (WEXITSTATUS(status) < 0) {
8837c478bd9Sstevel@tonic-gate 		return (info->pd_idle_time * 60);
8847c478bd9Sstevel@tonic-gate 	} else {
8857c478bd9Sstevel@tonic-gate 		return (WEXITSTATUS(status) * 60);
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate }
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate static void
8907c478bd9Sstevel@tonic-gate set_alarm(time_t now)
8917c478bd9Sstevel@tonic-gate {
8927c478bd9Sstevel@tonic-gate 	time_t	itime, stime, next_time, max_time;
8937c478bd9Sstevel@tonic-gate 	int	next_alarm;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	max_time = MAX(checkidle_time, shutdown_time);
8967c478bd9Sstevel@tonic-gate 	if (max_time == 0) {
8977c478bd9Sstevel@tonic-gate 		(void) alarm(0);
8987c478bd9Sstevel@tonic-gate 		return;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 	itime = (checkidle_time == 0) ? max_time : checkidle_time;
9017c478bd9Sstevel@tonic-gate 	stime = (shutdown_time == 0) ? max_time : shutdown_time;
9027c478bd9Sstevel@tonic-gate 	next_time = MIN(itime, stime);
9037c478bd9Sstevel@tonic-gate 	next_alarm = (next_time <= now) ? 1 : (next_time - now);
9047c478bd9Sstevel@tonic-gate 	(void) alarm(next_alarm);
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate #ifdef DEBUG
9077c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Currently @ %s", ctime(&now));
9087c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Checkidle in %d secs\n", checkidle_time - now);
9097c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Shutdown  in %d secs\n", shutdown_time - now);
9107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Next alarm goes off in %d secs\n", next_alarm);
9117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "************************************\n");
9127c478bd9Sstevel@tonic-gate #endif
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate static int
916*c42872d4Smh27603 poweroff(const char *msg, char **cmd_argv)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
9197c478bd9Sstevel@tonic-gate 	pid_t		pid, child;
9207c478bd9Sstevel@tonic-gate 	struct passwd	*pwd;
9217c478bd9Sstevel@tonic-gate 	char		*home, *user;
9227c478bd9Sstevel@tonic-gate 	char		ehome[] = "HOME=";
9237c478bd9Sstevel@tonic-gate 	char		euser[] = "LOGNAME=";
9247c478bd9Sstevel@tonic-gate 	int		status;
9257c478bd9Sstevel@tonic-gate 	char		**ca;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (mutex_trylock(&poweroff_mutex) != 0)
9287c478bd9Sstevel@tonic-gate 		return (0);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	if (stat("/dev/console", &statbuf) == -1 ||
9317c478bd9Sstevel@tonic-gate 	    (pwd = getpwuid(statbuf.st_uid)) == NULL) {
9327c478bd9Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9337c478bd9Sstevel@tonic-gate 		return (1);
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	if (msg)
9377c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE, msg);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	if (*cmd_argv == NULL) {
9407c478bd9Sstevel@tonic-gate 		logerror("No command to run.");
9417c478bd9Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9427c478bd9Sstevel@tonic-gate 		return (1);
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	home = malloc(strlen(pwd->pw_dir) + sizeof (ehome));
9467c478bd9Sstevel@tonic-gate 	user = malloc(strlen(pwd->pw_name) + sizeof (euser));
9477c478bd9Sstevel@tonic-gate 	if (home == NULL || user == NULL) {
9487c478bd9Sstevel@tonic-gate 		free(home);
9497c478bd9Sstevel@tonic-gate 		free(user);
9507c478bd9Sstevel@tonic-gate 		logerror("No memory.");
9517c478bd9Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9527c478bd9Sstevel@tonic-gate 		return (1);
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 	(void) strcpy(home, ehome);
9557c478bd9Sstevel@tonic-gate 	(void) strcat(home, pwd->pw_dir);
9567c478bd9Sstevel@tonic-gate 	(void) strcpy(user, euser);
9577c478bd9Sstevel@tonic-gate 	(void) strcat(user, pwd->pw_name);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * Need to simulate the user enviroment, minimaly set HOME, and USER.
9617c478bd9Sstevel@tonic-gate 	 */
9627c478bd9Sstevel@tonic-gate 	if ((child = fork1()) == 0) {
9637c478bd9Sstevel@tonic-gate 		(void) putenv(home);
9647c478bd9Sstevel@tonic-gate 		(void) putenv(user);
9657c478bd9Sstevel@tonic-gate 		(void) setgid(pwd->pw_gid);
9667c478bd9Sstevel@tonic-gate 		(void) setuid(pwd->pw_uid);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		/*
9697c478bd9Sstevel@tonic-gate 		 * check for shutdown flag and set environment
9707c478bd9Sstevel@tonic-gate 		 */
9717c478bd9Sstevel@tonic-gate 		for (ca = cmd_argv; *ca; ca++) {
9727c478bd9Sstevel@tonic-gate 			if (strcmp("-h", *ca) == 0) {
9737c478bd9Sstevel@tonic-gate 				(void) putenv("SYSSUSPENDDODEFAULT=");
9747c478bd9Sstevel@tonic-gate 				break;
9757c478bd9Sstevel@tonic-gate 			}
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		(void) execv(cmd_argv[0], cmd_argv);
9797c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
9807c478bd9Sstevel@tonic-gate 	} else {
9817c478bd9Sstevel@tonic-gate 		free(home);
9827c478bd9Sstevel@tonic-gate 		free(user);
9837c478bd9Sstevel@tonic-gate 		if (child == -1) {
9847c478bd9Sstevel@tonic-gate 			mutex_unlock(&poweroff_mutex);
9857c478bd9Sstevel@tonic-gate 			return (1);
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 	pid = 0;
9897c478bd9Sstevel@tonic-gate 	while (pid != child)
9907c478bd9Sstevel@tonic-gate 		pid = wait(&status);
9917c478bd9Sstevel@tonic-gate 	if (WEXITSTATUS(status)) {
9927c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "Failed to exec \"%s\".", cmd_argv[0]);
9937c478bd9Sstevel@tonic-gate 		mutex_unlock(&poweroff_mutex);
9947c478bd9Sstevel@tonic-gate 		return (1);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	mutex_unlock(&poweroff_mutex);
9987c478bd9Sstevel@tonic-gate 	return (0);
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate #define	PBUFSIZE	256
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate /*
10047c478bd9Sstevel@tonic-gate  * Gets the value of a prom property at either root or options node.  It
10057c478bd9Sstevel@tonic-gate  * returns 1 if it is successful, otherwise it returns 0 .
10067c478bd9Sstevel@tonic-gate  */
10077c478bd9Sstevel@tonic-gate static int
10087c478bd9Sstevel@tonic-gate get_prom(int prom_fd, prom_node_t node_name,
10097c478bd9Sstevel@tonic-gate 	char *property_name, char *property_value, size_t len)
10107c478bd9Sstevel@tonic-gate {
10117c478bd9Sstevel@tonic-gate 	union {
10127c478bd9Sstevel@tonic-gate 		char buf[PBUFSIZE + sizeof (uint_t)];
10137c478bd9Sstevel@tonic-gate 		struct openpromio opp;
10147c478bd9Sstevel@tonic-gate 	} oppbuf;
10157c478bd9Sstevel@tonic-gate 	register struct openpromio *opp = &(oppbuf.opp);
10167c478bd9Sstevel@tonic-gate 	int	got_it = 0;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	if (prom_fd == -1) {
10197c478bd9Sstevel@tonic-gate 		return (0);
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	switch (node_name) {
10237c478bd9Sstevel@tonic-gate 	case root:
10247c478bd9Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
10257c478bd9Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10267c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNEXT, opp) < 0) {
10277c478bd9Sstevel@tonic-gate 			return (0);
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		/*
10317c478bd9Sstevel@tonic-gate 		 * Passing null string will give us the first property.
10327c478bd9Sstevel@tonic-gate 		 */
10337c478bd9Sstevel@tonic-gate 		(void *) memset(oppbuf.buf, 0, PBUFSIZE);
10347c478bd9Sstevel@tonic-gate 		do {
10357c478bd9Sstevel@tonic-gate 			opp->oprom_size = PBUFSIZE;
10367c478bd9Sstevel@tonic-gate 			if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) {
10377c478bd9Sstevel@tonic-gate 				return (0);
10387c478bd9Sstevel@tonic-gate 			}
10397c478bd9Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, property_name) == 0) {
10407c478bd9Sstevel@tonic-gate 				got_it++;
10417c478bd9Sstevel@tonic-gate 				break;
10427c478bd9Sstevel@tonic-gate 			}
10437c478bd9Sstevel@tonic-gate 		} while (opp->oprom_size > 0);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 		if (!got_it) {
10467c478bd9Sstevel@tonic-gate 			return (0);
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 		if (got_it && property_value == NULL) {
10497c478bd9Sstevel@tonic-gate 			return (1);
10507c478bd9Sstevel@tonic-gate 		}
10517c478bd9Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10527c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) {
10537c478bd9Sstevel@tonic-gate 			return (0);
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
10567c478bd9Sstevel@tonic-gate 			*property_value = '\0';
10577c478bd9Sstevel@tonic-gate 		} else {
10587c478bd9Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
10597c478bd9Sstevel@tonic-gate 		}
10607c478bd9Sstevel@tonic-gate 		break;
10617c478bd9Sstevel@tonic-gate 	case options:
10627c478bd9Sstevel@tonic-gate 		estrcpy(opp->oprom_array, property_name, PBUFSIZE);
10637c478bd9Sstevel@tonic-gate 		opp->oprom_size = PBUFSIZE;
10647c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
10657c478bd9Sstevel@tonic-gate 			return (0);
10667c478bd9Sstevel@tonic-gate 		}
10677c478bd9Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
10687c478bd9Sstevel@tonic-gate 			return (0);
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 		if (property_value != NULL) {
10717c478bd9Sstevel@tonic-gate 			estrcpy(property_value, opp->oprom_array, len);
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 		break;
10747c478bd9Sstevel@tonic-gate 	default:
10757c478bd9Sstevel@tonic-gate 		logerror("Only root node and options node are supported.\n");
10767c478bd9Sstevel@tonic-gate 		return (0);
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	return (1);
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate #define	isspace(ch)	((ch) == ' ' || (ch) == '\t')
10837c478bd9Sstevel@tonic-gate #define	iseol(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10867c478bd9Sstevel@tonic-gate static void
10877c478bd9Sstevel@tonic-gate power_button_monitor(void *arg)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	struct pollfd pfd;
10907c478bd9Sstevel@tonic-gate 	int events;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) {
10937c478bd9Sstevel@tonic-gate 		logerror("Failed to monitor the power button.");
10947c478bd9Sstevel@tonic-gate 		thr_exit((void *) 0);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	pfd.fd = pb_fd;
10987c478bd9Sstevel@tonic-gate 	pfd.events = POLLIN;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
11017c478bd9Sstevel@tonic-gate 	while (1) {
11027c478bd9Sstevel@tonic-gate 		if (poll(&pfd, 1, INFTIM) == -1) {
11037c478bd9Sstevel@tonic-gate 			logerror("Failed to poll for power button events.");
11047c478bd9Sstevel@tonic-gate 			thr_exit((void *) 0);
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		if (!(pfd.revents & POLLIN))
11087c478bd9Sstevel@tonic-gate 			continue;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
11117c478bd9Sstevel@tonic-gate 			logerror("Failed to get power button events.");
11127c478bd9Sstevel@tonic-gate 			thr_exit((void *) 0);
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 		if ((events & PB_BUTTON_PRESS) &&
11167c478bd9Sstevel@tonic-gate 		    (poweroff(NULL, power_button_cmd) != 0)) {
11177c478bd9Sstevel@tonic-gate 			logerror("Power button is pressed, powering "
11187c478bd9Sstevel@tonic-gate 			    "down the system!");
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 			/*
11217c478bd9Sstevel@tonic-gate 			 * Send SIGPWR signal to the init process to
11227c478bd9Sstevel@tonic-gate 			 * shut down the system.
11237c478bd9Sstevel@tonic-gate 			 */
11247c478bd9Sstevel@tonic-gate 			if (kill(1, SIGPWR) == -1)
11257c478bd9Sstevel@tonic-gate 				(void) uadmin(A_SHUTDOWN, AD_POWEROFF, 0);
11267c478bd9Sstevel@tonic-gate 		}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 		/*
11297c478bd9Sstevel@tonic-gate 		 * Clear any power button event that has happened
11307c478bd9Sstevel@tonic-gate 		 * meanwhile we were busy processing the last one.
11317c478bd9Sstevel@tonic-gate 		 */
11327c478bd9Sstevel@tonic-gate 		if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
11337c478bd9Sstevel@tonic-gate 			logerror("Failed to get power button events.");
11347c478bd9Sstevel@tonic-gate 			thr_exit((void *) 0);
11357c478bd9Sstevel@tonic-gate 		}
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate #ifdef sparc
11407c478bd9Sstevel@tonic-gate static void
11417c478bd9Sstevel@tonic-gate do_attach(void)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	if (read_cpr_config() < 0)
11447c478bd9Sstevel@tonic-gate 		return;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	/*
11477c478bd9Sstevel@tonic-gate 	 * If autopm behavior is explicitly enabled for energystar-v2, or
11487c478bd9Sstevel@tonic-gate 	 * set to default for energystar-v3, create a new thread to attach
11497c478bd9Sstevel@tonic-gate 	 * all devices.
11507c478bd9Sstevel@tonic-gate 	 */
11517c478bd9Sstevel@tonic-gate 	estar_v3_prop = asinfo.is_autopm_default;
11527c478bd9Sstevel@tonic-gate 	if ((strcmp(asinfo.apm_behavior, "enable") == 0) ||
11537c478bd9Sstevel@tonic-gate 	    (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) {
11547c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, NULL, attach_devices, NULL,
11557c478bd9Sstevel@tonic-gate 		    THR_DAEMON, NULL) != 0) {
11567c478bd9Sstevel@tonic-gate 			logerror("Unable to create thread to attach devices.");
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 	}
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11627c478bd9Sstevel@tonic-gate static void *
11637c478bd9Sstevel@tonic-gate attach_devices(void *arg)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate 	di_node_t root_node;
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	sleep(60);	/* let booting finish first */
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) {
11707c478bd9Sstevel@tonic-gate 		logerror("Failed to attach devices.");
11717c478bd9Sstevel@tonic-gate 		return (NULL);
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 	di_fini(root_node);
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/*
11767c478bd9Sstevel@tonic-gate 	 * Unload all the modules.
11777c478bd9Sstevel@tonic-gate 	 */
11787c478bd9Sstevel@tonic-gate 	(void) modctl(MODUNLOAD, 0);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	return (NULL);
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate #endif
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate /*
11867c478bd9Sstevel@tonic-gate  * Create a file which will contain our pid.  Pmconfig will check this file
11877c478bd9Sstevel@tonic-gate  * to see if we are running and can use the pid to signal us.  Returns the
11887c478bd9Sstevel@tonic-gate  * file descriptor if successful, -1 otherwise.
11897c478bd9Sstevel@tonic-gate  *
11907c478bd9Sstevel@tonic-gate  * Note: Deal with attempt to launch multiple instances and also with existence
11917c478bd9Sstevel@tonic-gate  * of an obsolete pid file caused by an earlier abort.
11927c478bd9Sstevel@tonic-gate  */
11937c478bd9Sstevel@tonic-gate static int
11947c478bd9Sstevel@tonic-gate open_pidfile(char *me)
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	int fd;
1197*c42872d4Smh27603 	const char *e1 = "%s: Cannot open pid file for read: ";
1198*c42872d4Smh27603 	const char *e2 = "%s: Cannot unlink obsolete pid file: ";
1199*c42872d4Smh27603 	const char *e3 = "%s: Cannot open /proc for pid %ld: ";
1200*c42872d4Smh27603 	const char *e4 = "%s: Cannot read /proc for pid %ld: ";
1201*c42872d4Smh27603 	const char *e5 = "%s: Another instance (pid %ld) is trying to exit"
12027c478bd9Sstevel@tonic-gate 			"and may be hung.  Please contact sysadmin.\n";
1203*c42872d4Smh27603 	const char *e6 = "%s: Another daemon is running\n";
1204*c42872d4Smh27603 	const char *e7 = "%s: Cannot create pid file: ";
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate again:
12077c478bd9Sstevel@tonic-gate 	if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) {
12087c478bd9Sstevel@tonic-gate 		if (errno  == EEXIST) {
12097c478bd9Sstevel@tonic-gate 			FILE *fp;
12107c478bd9Sstevel@tonic-gate 			int ps_fd;
12117c478bd9Sstevel@tonic-gate 			pid_t pid;
12127c478bd9Sstevel@tonic-gate 			psinfo_t ps_info;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 			if ((fp = fopen(pidpath, "r")) == NULL) {
12157c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, e1, me);
12167c478bd9Sstevel@tonic-gate 				perror(NULL);
12177c478bd9Sstevel@tonic-gate 				return (-1);
12187c478bd9Sstevel@tonic-gate 			}
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 			/* Read the pid */
12217c478bd9Sstevel@tonic-gate 			pid = (pid_t)-1;
12227c478bd9Sstevel@tonic-gate 			(void) fscanf(fp, "%ld", &pid);
12237c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
12247c478bd9Sstevel@tonic-gate 			if (pid == -1) {
12257c478bd9Sstevel@tonic-gate 				if (unlink(pidpath) == -1) {
12267c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, e2, me);
12277c478bd9Sstevel@tonic-gate 					perror(NULL);
12287c478bd9Sstevel@tonic-gate 					return (-1);
12297c478bd9Sstevel@tonic-gate 				} else /* try without corrupted file */
12307c478bd9Sstevel@tonic-gate 					goto again;
12317c478bd9Sstevel@tonic-gate 			}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 			/* Is pid for a running process? */
12347c478bd9Sstevel@tonic-gate 			(void) sprintf(scratch, "/proc/%ld/psinfo", pid);
12357c478bd9Sstevel@tonic-gate 			ps_fd = open(scratch, O_RDONLY | O_NDELAY);
12367c478bd9Sstevel@tonic-gate 			if (ps_fd == -1) {
12377c478bd9Sstevel@tonic-gate 				if (errno == ENOENT) {
12387c478bd9Sstevel@tonic-gate 					if (unlink(pidpath) == -1) {
12397c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr, e2, me);
12407c478bd9Sstevel@tonic-gate 						perror(NULL);
12417c478bd9Sstevel@tonic-gate 						return (-1);
12427c478bd9Sstevel@tonic-gate 					} else	/* try without obsolete file */
12437c478bd9Sstevel@tonic-gate 						goto again;
12447c478bd9Sstevel@tonic-gate 				}
12457c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, e3, me, pid);
12467c478bd9Sstevel@tonic-gate 				return (-1);
12477c478bd9Sstevel@tonic-gate 			}
12487c478bd9Sstevel@tonic-gate 			if (read(ps_fd, &ps_info,
12497c478bd9Sstevel@tonic-gate 			    sizeof (ps_info)) != sizeof (ps_info)) {
12507c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, e4, me, pid);
12517c478bd9Sstevel@tonic-gate 				perror(NULL);
12527c478bd9Sstevel@tonic-gate 				(void) close(ps_fd);
12537c478bd9Sstevel@tonic-gate 				return (-1);
12547c478bd9Sstevel@tonic-gate 			}
12557c478bd9Sstevel@tonic-gate 			(void) close(ps_fd);
12567c478bd9Sstevel@tonic-gate 			if (ps_info.pr_nlwp == 0) {	/* defunct process */
12577c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, e5, me, pid);
12587c478bd9Sstevel@tonic-gate 				return (-1);
12597c478bd9Sstevel@tonic-gate 			} else {	/* instance of daemon already running */
12607c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, e6, me);
12617c478bd9Sstevel@tonic-gate 				return (-1);
12627c478bd9Sstevel@tonic-gate 			}
12637c478bd9Sstevel@tonic-gate 		} else {	/* create failure not due to existing file */
12647c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, e7, me);
12657c478bd9Sstevel@tonic-gate 			perror(NULL);
12667c478bd9Sstevel@tonic-gate 			return (-1);
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	(void) fchown(fd, (uid_t)-1, (gid_t)0);
12717c478bd9Sstevel@tonic-gate 	return (fd);
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate  * Write a pid to the pid file.  Report errors to syslog.
12767c478bd9Sstevel@tonic-gate  *
12777c478bd9Sstevel@tonic-gate  */
12787c478bd9Sstevel@tonic-gate static int
12797c478bd9Sstevel@tonic-gate write_pidfile(int fd, pid_t pid)
12807c478bd9Sstevel@tonic-gate {
12817c478bd9Sstevel@tonic-gate 	int	len;
12827c478bd9Sstevel@tonic-gate 	int	rc = 0;			/* assume success */
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	len = sprintf(scratch, "%ld\n", pid);
12857c478bd9Sstevel@tonic-gate 	if (write(fd, scratch, len) != len) {
12867c478bd9Sstevel@tonic-gate 		logerror("Cannot write pid file: %s", strerror(errno));
12877c478bd9Sstevel@tonic-gate 		rc = -1;
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	return (rc);
12917c478bd9Sstevel@tonic-gate }
1292