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
5c42872d4Smh * Common Development and Distribution License (the "License").
6c42872d4Smh * 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 /*
22623ec8b0SRandy Fishel * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
2413c646d3SAlexander Eremin * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate */
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 <dirent.h>
367c478bd9Sstevel@tonic-gate #include <thread.h>
377c478bd9Sstevel@tonic-gate #include <limits.h>
387c478bd9Sstevel@tonic-gate #include <sys/todio.h> /* Time-Of-Day chip */
397c478bd9Sstevel@tonic-gate #include <sys/stat.h>
407c478bd9Sstevel@tonic-gate #include <sys/wait.h>
417c478bd9Sstevel@tonic-gate #include <sys/ipc.h> /* IPC functions */
427c478bd9Sstevel@tonic-gate #include <signal.h> /* signal handling */
437c478bd9Sstevel@tonic-gate #include <syslog.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
467c478bd9Sstevel@tonic-gate #include <poll.h>
477c478bd9Sstevel@tonic-gate #include <sys/pm.h> /* power management driver */
487c478bd9Sstevel@tonic-gate #include <sys/uadmin.h>
497c478bd9Sstevel@tonic-gate #include <sys/openpromio.h> /* for prom access */
507c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> /* for MIN & MAX macros */
517c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
527c478bd9Sstevel@tonic-gate #include <sys/stropts.h> /* for INFTIM */
537c478bd9Sstevel@tonic-gate #include <sys/pbio.h>
547c478bd9Sstevel@tonic-gate #include <sys/cpr.h>
552df1fe9cSrandyf #include <sys/srn.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"
762df1fe9cSrandyf #define SRN "/dev/srn"
777c478bd9Sstevel@tonic-gate #define LOGFILE "./powerd.log"
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate #define PBM_THREAD 0
807c478bd9Sstevel@tonic-gate #define ATTACH_THREAD 1
817c478bd9Sstevel@tonic-gate #define NUM_THREADS 2
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate #define CHECK_INTERVAL 5
847c478bd9Sstevel@tonic-gate #define IDLECHK_INTERVAL 15
857c478bd9Sstevel@tonic-gate #define MINS_TO_SECS 60
867c478bd9Sstevel@tonic-gate #define HOURS_TO_SECS (60 * 60)
877c478bd9Sstevel@tonic-gate #define DAYS_TO_SECS (24 * 60 * 60)
887c478bd9Sstevel@tonic-gate #define HOURS_TO_MINS 60
897c478bd9Sstevel@tonic-gate #define DAYS_TO_MINS (24 * 60)
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate #define LIFETIME_SECS (7 * 365 * DAYS_TO_SECS)
927c478bd9Sstevel@tonic-gate #define DEFAULT_POWER_CYCLE_LIMIT 10000
937c478bd9Sstevel@tonic-gate #define DEFAULT_SYSTEM_BOARD_DATE 804582000 /* July 1, 1995 */
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate #define LLEN 80
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate typedef enum {root, options} prom_node_t;
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /* State Variables */
1007c478bd9Sstevel@tonic-gate static struct cprconfig asinfo;
1017c478bd9Sstevel@tonic-gate static time_t shutdown_time; /* Time for next shutdown check */
1027c478bd9Sstevel@tonic-gate static time_t checkidle_time; /* Time for next idleness check */
1037c478bd9Sstevel@tonic-gate static time_t last_resume;
1047c478bd9Sstevel@tonic-gate pwr_info_t *info; /* private as config data buffer */
1057c478bd9Sstevel@tonic-gate static int pb_fd; /* power button driver */
1067c478bd9Sstevel@tonic-gate static int broadcast; /* Enables syslog messages */
1077c478bd9Sstevel@tonic-gate static int start_calc;
1087c478bd9Sstevel@tonic-gate static int autoshutdown_en;
1097c478bd9Sstevel@tonic-gate static int do_idlecheck;
1107c478bd9Sstevel@tonic-gate static int got_sighup;
1117c478bd9Sstevel@tonic-gate static int estar_v2_prop;
1127c478bd9Sstevel@tonic-gate static int estar_v3_prop;
1137c478bd9Sstevel@tonic-gate static int log_power_cycles_error = 0;
1147c478bd9Sstevel@tonic-gate static int log_system_board_date_error = 0;
1157c478bd9Sstevel@tonic-gate static int log_no_autoshutdown_warning = 0;
1167c478bd9Sstevel@tonic-gate static mutex_t poweroff_mutex;
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate static char *autoshutdown_cmd[] = {
119623ec8b0SRandy Fishel "/usr/bin/sys-suspend",
1207c478bd9Sstevel@tonic-gate "-n", "-d", ":0", NULL
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate static char *power_button_cmd[] = {
124623ec8b0SRandy Fishel "/usr/bin/sys-suspend",
1257c478bd9Sstevel@tonic-gate "-h", "-d", ":0", NULL
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate
12813c646d3SAlexander Eremin #ifdef __x86
1292df1fe9cSrandyf static char *autoS3_cmd[] = {
130623ec8b0SRandy Fishel "/usr/bin/sys-suspend",
1312df1fe9cSrandyf "-n", "-d", ":0", NULL
1322df1fe9cSrandyf };
13313c646d3SAlexander Eremin #endif
1342df1fe9cSrandyf
1357c478bd9Sstevel@tonic-gate static char pidpath[] = PIDPATH;
1367c478bd9Sstevel@tonic-gate static char scratch[PATH_MAX];
1377c478bd9Sstevel@tonic-gate static char *prog;
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate /* Local Functions */
1407c478bd9Sstevel@tonic-gate static void alarm_handler(int);
1417c478bd9Sstevel@tonic-gate static void thaw_handler(int);
1427c478bd9Sstevel@tonic-gate static void kill_handler(int);
1437c478bd9Sstevel@tonic-gate static void work_handler(int);
1447c478bd9Sstevel@tonic-gate static void check_shutdown(time_t *, hrtime_t *);
1457c478bd9Sstevel@tonic-gate static void check_idleness(time_t *, hrtime_t *);
1467c478bd9Sstevel@tonic-gate static int last_system_activity(hrtime_t *);
1477c478bd9Sstevel@tonic-gate static int run_idlecheck(void);
1487c478bd9Sstevel@tonic-gate static void set_alarm(time_t);
149c42872d4Smh static int poweroff(const char *, char **);
1507c478bd9Sstevel@tonic-gate static int is_ok2shutdown(time_t *);
1517c478bd9Sstevel@tonic-gate static int get_prom(int, prom_node_t, char *, char *, size_t);
15245057a1aSToomas Soome static void *power_button_monitor(void *);
1537c478bd9Sstevel@tonic-gate static int open_pidfile(char *);
1547c478bd9Sstevel@tonic-gate static int write_pidfile(int, pid_t);
1557c478bd9Sstevel@tonic-gate static int read_cpr_config(void);
15645057a1aSToomas Soome static void *system_activity_monitor(void *);
15713c646d3SAlexander Eremin #ifdef __x86
15845057a1aSToomas Soome static void *autos3_monitor(void *);
15913c646d3SAlexander Eremin #endif
1607c478bd9Sstevel@tonic-gate static void do_attach(void);
1617c478bd9Sstevel@tonic-gate static void *attach_devices(void *);
1622df1fe9cSrandyf static int powerd_debug;
1637c478bd9Sstevel@tonic-gate
164c42872d4Smh /* PRINTFLIKE1 */
1657c478bd9Sstevel@tonic-gate static void
logerror(const char * fmt,...)166c42872d4Smh logerror(const char *fmt, ...)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate va_list args;
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate va_start(args, fmt);
1717c478bd9Sstevel@tonic-gate if (broadcast)
1727c478bd9Sstevel@tonic-gate vsyslog(LOG_ERR, fmt, args);
1737c478bd9Sstevel@tonic-gate va_end(args);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate static void
estrcpy(char * dst,char * src,size_t dlen)1787c478bd9Sstevel@tonic-gate estrcpy(char *dst, char *src, size_t dlen)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate size_t slen;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate slen = strlcpy(dst, src, dlen);
1837c478bd9Sstevel@tonic-gate if (slen >= dlen) {
1847c478bd9Sstevel@tonic-gate logerror("%s: string too long \"%s ...\"\n"
1857c478bd9Sstevel@tonic-gate "(len %d, max %d)\n", prog, dst, slen, dlen - 1);
1867c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])1927c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate pid_t pid;
1957c478bd9Sstevel@tonic-gate int pm_fd;
1967c478bd9Sstevel@tonic-gate struct sigaction act;
1977c478bd9Sstevel@tonic-gate sigset_t sigmask;
1987c478bd9Sstevel@tonic-gate int c;
1997c478bd9Sstevel@tonic-gate char errmsg[PATH_MAX + 64];
2007c478bd9Sstevel@tonic-gate int pid_fd;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate prog = argv[0];
2037c478bd9Sstevel@tonic-gate if (geteuid() != 0) {
2047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: Must be root\n", prog);
2057c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate if ((pid_fd = open_pidfile(prog)) == -1)
2097c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * Process options
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate broadcast = 1;
2152df1fe9cSrandyf while ((c = getopt(argc, argv, "nd")) != EOF) {
2167c478bd9Sstevel@tonic-gate switch (c) {
2172df1fe9cSrandyf case 'd':
2182df1fe9cSrandyf powerd_debug = 1;
2192df1fe9cSrandyf break;
2207c478bd9Sstevel@tonic-gate case 'n':
2217c478bd9Sstevel@tonic-gate broadcast = 0;
2227c478bd9Sstevel@tonic-gate break;
2237c478bd9Sstevel@tonic-gate case '?':
2247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Usage: %s [-n]\n", prog);
2257c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate pm_fd = open(PM, O_RDWR);
2307c478bd9Sstevel@tonic-gate if (pm_fd == -1) {
231c42872d4Smh (void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM);
2327c478bd9Sstevel@tonic-gate perror(errmsg);
2337c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate (void) close(pm_fd);
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate * Initialize mutex lock used to insure only one command to
2397c478bd9Sstevel@tonic-gate * run at a time.
2407c478bd9Sstevel@tonic-gate */
2417c478bd9Sstevel@tonic-gate if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) {
2427c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2432df1fe9cSrandyf "%s: Unable to initialize mutex lock\n", prog);
2447c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) {
248c42872d4Smh (void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog);
2497c478bd9Sstevel@tonic-gate perror(errmsg);
2507c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate * Daemon is set to go...
2557c478bd9Sstevel@tonic-gate */
2567c478bd9Sstevel@tonic-gate if ((pid = fork()) < 0)
2577c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2587c478bd9Sstevel@tonic-gate else if (pid != 0)
2597c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS);
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate pid = getpid();
2627c478bd9Sstevel@tonic-gate openlog(prog, 0, LOG_DAEMON);
2637c478bd9Sstevel@tonic-gate if (write_pidfile(pid_fd, pid) == -1) /* logs errors on failure */
2647c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2657c478bd9Sstevel@tonic-gate (void) close(pid_fd);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate * Close all the parent's file descriptors (Bug 1225843).
2697c478bd9Sstevel@tonic-gate */
2707c478bd9Sstevel@tonic-gate closefrom(0);
2717c478bd9Sstevel@tonic-gate (void) setsid();
2727c478bd9Sstevel@tonic-gate (void) chdir("/");
2737c478bd9Sstevel@tonic-gate (void) umask(0);
2747c478bd9Sstevel@tonic-gate #ifdef DEBUG
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate * Connect stdout to the console.
2777c478bd9Sstevel@tonic-gate */
2787c478bd9Sstevel@tonic-gate if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) {
2797c478bd9Sstevel@tonic-gate logerror("Unable to connect to the console.");
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate #endif
2827c478bd9Sstevel@tonic-gate info->pd_flags = PD_AC;
2837c478bd9Sstevel@tonic-gate info->pd_idle_time = -1;
2847c478bd9Sstevel@tonic-gate info->pd_start_time = 0;
2857c478bd9Sstevel@tonic-gate info->pd_finish_time = 0;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
2897c478bd9Sstevel@tonic-gate * any time
2907c478bd9Sstevel@tonic-gate */
2917c478bd9Sstevel@tonic-gate act.sa_handler = kill_handler;
2927c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask);
2937c478bd9Sstevel@tonic-gate act.sa_flags = 0;
2947c478bd9Sstevel@tonic-gate (void) sigaction(SIGQUIT, &act, NULL);
2957c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &act, NULL);
2967c478bd9Sstevel@tonic-gate (void) sigaction(SIGTERM, &act, NULL);
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate (void) sigfillset(&sigmask);
2997c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGQUIT);
3007c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGINT);
3017c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGTERM);
3027c478bd9Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * If "power_button" device node can be opened, create a new
3067c478bd9Sstevel@tonic-gate * thread to monitor the power button.
3077c478bd9Sstevel@tonic-gate */
3087c478bd9Sstevel@tonic-gate if ((pb_fd = open(PB, O_RDONLY)) != -1) {
3092df1fe9cSrandyf if (powerd_debug)
3102df1fe9cSrandyf logerror("powerd starting power button monitor.");
31145057a1aSToomas Soome if (thr_create(NULL, 0, power_button_monitor, NULL,
3127c478bd9Sstevel@tonic-gate THR_DAEMON, NULL) != 0) {
3137c478bd9Sstevel@tonic-gate logerror("Unable to monitor system's power button.");
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate do_attach();
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate * Create a new thread to monitor system activity and suspend
3217c478bd9Sstevel@tonic-gate * system if idle.
3227c478bd9Sstevel@tonic-gate */
3232df1fe9cSrandyf if (powerd_debug)
3242df1fe9cSrandyf logerror("powerd starting system activity monitor.");
32545057a1aSToomas Soome if (thr_create(NULL, 0, system_activity_monitor, NULL,
3267c478bd9Sstevel@tonic-gate THR_DAEMON, NULL) != 0) {
3277c478bd9Sstevel@tonic-gate logerror("Unable to create thread to monitor system activity.");
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
33013c646d3SAlexander Eremin #ifdef __x86
3312df1fe9cSrandyf /*
3322df1fe9cSrandyf * Create a new thread to handle autos3 trigger
3332df1fe9cSrandyf */
3342df1fe9cSrandyf if (powerd_debug)
3352df1fe9cSrandyf logerror("powerd starting autos3 monitor.");
33645057a1aSToomas Soome if (thr_create(NULL, 0, autos3_monitor, NULL, THR_DAEMON,
33745057a1aSToomas Soome NULL) != 0) {
3382df1fe9cSrandyf logerror("Unable to create thread to monitor autos3 activity.");
3392df1fe9cSrandyf }
34013c646d3SAlexander Eremin #endif
3412df1fe9cSrandyf
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate * Block until we receive an explicit terminate signal
3447c478bd9Sstevel@tonic-gate */
3457c478bd9Sstevel@tonic-gate (void) sigsuspend(&sigmask);
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate return (1);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate
35045057a1aSToomas Soome static void *
system_activity_monitor(void * arg __unused)35145057a1aSToomas Soome system_activity_monitor(void *arg __unused)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate struct sigaction act;
3547c478bd9Sstevel@tonic-gate sigset_t sigmask;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * Setup for gathering system's statistic.
3587c478bd9Sstevel@tonic-gate */
3597c478bd9Sstevel@tonic-gate sysstat_init();
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate * In addition to the SIGQUIT, SIGINT and SIGTERM signals already
3637c478bd9Sstevel@tonic-gate * being handled, this thread also needs to handle SIGHUP, SIGALRM
3647c478bd9Sstevel@tonic-gate * and SIGTHAW signals.
3657c478bd9Sstevel@tonic-gate */
3667c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask);
3677c478bd9Sstevel@tonic-gate act.sa_flags = 0;
3687c478bd9Sstevel@tonic-gate act.sa_handler = alarm_handler;
3697c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL);
3707c478bd9Sstevel@tonic-gate act.sa_handler = work_handler;
3717c478bd9Sstevel@tonic-gate (void) sigaction(SIGHUP, &act, NULL);
3727c478bd9Sstevel@tonic-gate act.sa_handler = thaw_handler;
3737c478bd9Sstevel@tonic-gate (void) sigaction(SIGTHAW, &act, NULL);
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * Invoke work_handler with a dummy SIGHUP signal to read
3777c478bd9Sstevel@tonic-gate * cpr config file, get autoshutdown properties and schedule
3787c478bd9Sstevel@tonic-gate * an alarm if needed.
3797c478bd9Sstevel@tonic-gate */
3807c478bd9Sstevel@tonic-gate work_handler(SIGHUP);
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate * Wait for signal to read file
3847c478bd9Sstevel@tonic-gate */
3857c478bd9Sstevel@tonic-gate (void) thr_sigsetmask(0, 0, &sigmask);
3867c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGHUP);
3877c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGALRM);
3887c478bd9Sstevel@tonic-gate (void) sigdelset(&sigmask, SIGTHAW);
3897c478bd9Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
3907c478bd9Sstevel@tonic-gate do {
3917c478bd9Sstevel@tonic-gate (void) sigsuspend(&sigmask);
3927c478bd9Sstevel@tonic-gate } while (errno == EINTR);
39345057a1aSToomas Soome return (NULL);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate
39613c646d3SAlexander Eremin #ifdef __x86
39745057a1aSToomas Soome static void *
autos3_monitor(void * arg __unused)39845057a1aSToomas Soome autos3_monitor(void *arg __unused)
3992df1fe9cSrandyf {
4002df1fe9cSrandyf struct pollfd poll_fd;
4012df1fe9cSrandyf srn_event_info_t srn_event; /* contains suspend type */
4022df1fe9cSrandyf int fd, ret;
4032df1fe9cSrandyf
4042df1fe9cSrandyf fd = open(SRN, O_RDWR|O_EXCL|O_NDELAY);
4052df1fe9cSrandyf if (fd == -1) {
4062df1fe9cSrandyf logerror("Unable to open %s: %s", SRN, strerror(errno));
4075009f788SIgor Kozhukhov thr_exit((void *)(intptr_t)errno);
4082df1fe9cSrandyf }
4092df1fe9cSrandyf
4102df1fe9cSrandyf /*
4112df1fe9cSrandyf * Tell device we want the special sauce
4122df1fe9cSrandyf */
4132df1fe9cSrandyf ret = ioctl(fd, SRN_IOC_AUTOSX, NULL);
4142df1fe9cSrandyf if (ret == -1) {
4152df1fe9cSrandyf logerror("Ioctl SRN_IOC_AUTOSX failed: %s", strerror(errno));
41680148899SSurya Prakki (void) close(fd);
4175009f788SIgor Kozhukhov thr_exit((void *)(intptr_t)errno);
4182df1fe9cSrandyf }
4192df1fe9cSrandyf poll_fd.fd = fd;
4202df1fe9cSrandyf /*CONSTCOND*/
4212df1fe9cSrandyf while (1) {
4222df1fe9cSrandyf poll_fd.revents = 0;
4232df1fe9cSrandyf poll_fd.events = POLLIN;
4242df1fe9cSrandyf if (poll(&poll_fd, 1, -1) < 0) {
4252df1fe9cSrandyf switch (errno) {
4262df1fe9cSrandyf case EINTR:
4272df1fe9cSrandyf case EAGAIN:
4282df1fe9cSrandyf continue;
4292df1fe9cSrandyf default:
4302df1fe9cSrandyf logerror("Poll error: %s", strerror(errno));
43180148899SSurya Prakki (void) close(fd);
4325009f788SIgor Kozhukhov thr_exit((void *)(intptr_t)errno);
4332df1fe9cSrandyf }
4342df1fe9cSrandyf }
4352df1fe9cSrandyf
4362df1fe9cSrandyf ret = ioctl(fd, SRN_IOC_NEXTEVENT, &srn_event);
4372df1fe9cSrandyf if (ret == -1) {
4382df1fe9cSrandyf logerror("ioctl error: %s", strerror(errno));
43980148899SSurya Prakki (void) close(fd);
4405009f788SIgor Kozhukhov thr_exit((void *)(intptr_t)errno);
4412df1fe9cSrandyf }
4422df1fe9cSrandyf switch (srn_event.ae_type) {
4432df1fe9cSrandyf case 3: /* S3 */
4442df1fe9cSrandyf if (powerd_debug)
4452df1fe9cSrandyf logerror("ioctl returns type: %d",
4462df1fe9cSrandyf srn_event.ae_type);
4472df1fe9cSrandyf break;
4482df1fe9cSrandyf default:
4492df1fe9cSrandyf logerror("Unsupported target state %d",
4502df1fe9cSrandyf srn_event.ae_type);
4512df1fe9cSrandyf continue;
4522df1fe9cSrandyf }
4532df1fe9cSrandyf (void) poweroff("AutoS3", autoS3_cmd);
4542df1fe9cSrandyf continue;
4552df1fe9cSrandyf }
45645057a1aSToomas Soome return (NULL);
4572df1fe9cSrandyf }
45813c646d3SAlexander Eremin #endif
4592df1fe9cSrandyf
4607c478bd9Sstevel@tonic-gate static int
read_cpr_config(void)4617c478bd9Sstevel@tonic-gate read_cpr_config(void)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate int asfd;
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate if ((asfd = open(CPR_CONFIG, O_RDONLY)) < 0) {
4667c478bd9Sstevel@tonic-gate logerror("Unable to open CPR config file '%s'", CPR_CONFIG);
4677c478bd9Sstevel@tonic-gate return (-1);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate if (read(asfd, (void *)&asinfo, sizeof (asinfo)) != sizeof (asinfo)) {
4717c478bd9Sstevel@tonic-gate logerror("Unable to read CPR config file '%s'", CPR_CONFIG);
47280148899SSurya Prakki (void) close(asfd);
4737c478bd9Sstevel@tonic-gate return (-1);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate (void) close(asfd);
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate return (0);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4827c478bd9Sstevel@tonic-gate static void
thaw_handler(int sig)4837c478bd9Sstevel@tonic-gate thaw_handler(int sig)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate start_calc = 0;
4867c478bd9Sstevel@tonic-gate last_resume = time(NULL);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4907c478bd9Sstevel@tonic-gate static void
kill_handler(int sig)4917c478bd9Sstevel@tonic-gate kill_handler(int sig)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate int ret_code = EXIT_SUCCESS;
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate * Free resources
4977c478bd9Sstevel@tonic-gate */
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate free(info);
5007c478bd9Sstevel@tonic-gate if (pb_fd != -1) {
5017c478bd9Sstevel@tonic-gate (void) close(pb_fd);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate (void) mutex_destroy(&poweroff_mutex);
5047c478bd9Sstevel@tonic-gate (void) unlink(pidpath);
5057c478bd9Sstevel@tonic-gate closelog();
5067c478bd9Sstevel@tonic-gate exit(ret_code);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5107c478bd9Sstevel@tonic-gate static void
alarm_handler(int sig)5117c478bd9Sstevel@tonic-gate alarm_handler(int sig)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate time_t now;
5147c478bd9Sstevel@tonic-gate hrtime_t hr_now;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate now = time(NULL);
5177c478bd9Sstevel@tonic-gate hr_now = gethrtime();
5187c478bd9Sstevel@tonic-gate if (checkidle_time <= now && checkidle_time != 0)
5197c478bd9Sstevel@tonic-gate check_idleness(&now, &hr_now);
5207c478bd9Sstevel@tonic-gate if (shutdown_time <= now && shutdown_time != 0)
5217c478bd9Sstevel@tonic-gate check_shutdown(&now, &hr_now);
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate set_alarm(now);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5277c478bd9Sstevel@tonic-gate static void
work_handler(int sig)5287c478bd9Sstevel@tonic-gate work_handler(int sig)
5297c478bd9Sstevel@tonic-gate {
5307c478bd9Sstevel@tonic-gate time_t now;
5317c478bd9Sstevel@tonic-gate hrtime_t hr_now;
5327c478bd9Sstevel@tonic-gate struct stat stat_buf;
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate do_idlecheck = 0;
5357c478bd9Sstevel@tonic-gate info->pd_flags = PD_AC;
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Parse the config file for autoshutdown and idleness entries.
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate if (read_cpr_config() < 0)
5417c478bd9Sstevel@tonic-gate return;
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate * Since Oct. 1, 1995, any new system shipped had root
5457c478bd9Sstevel@tonic-gate * property "energystar-v2" defined in its prom. Systems
5467c478bd9Sstevel@tonic-gate * shipped after July 1, 1999, will have "energystar-v3"
5477c478bd9Sstevel@tonic-gate * property.
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate estar_v2_prop = asinfo.is_cpr_default;
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate info->pd_flags |= asinfo.is_autowakeup_capable;
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate if (strlen(asinfo.idlecheck_path) > 0) {
5547c478bd9Sstevel@tonic-gate if (stat(asinfo.idlecheck_path, &stat_buf) != 0) {
5557c478bd9Sstevel@tonic-gate logerror("unable to access idlecheck program \"%s\".",
5567c478bd9Sstevel@tonic-gate asinfo.idlecheck_path);
5577c478bd9Sstevel@tonic-gate } else if (!(stat_buf.st_mode & S_IXUSR)) {
5587c478bd9Sstevel@tonic-gate logerror("idlecheck program \"%s\" is not executable.",
5597c478bd9Sstevel@tonic-gate asinfo.idlecheck_path);
5607c478bd9Sstevel@tonic-gate } else {
5617c478bd9Sstevel@tonic-gate do_idlecheck = 1;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate if (strlen(asinfo.as_behavior) == 0 ||
5667c478bd9Sstevel@tonic-gate strcmp(asinfo.as_behavior, "noshutdown") == 0 ||
5677c478bd9Sstevel@tonic-gate strcmp(asinfo.as_behavior, "unconfigured") == 0) {
5687c478bd9Sstevel@tonic-gate info->pd_autoshutdown = 0;
5697c478bd9Sstevel@tonic-gate } else if (strcmp(asinfo.as_behavior, "default") == 0) {
5707c478bd9Sstevel@tonic-gate info->pd_autoshutdown = estar_v2_prop;
5717c478bd9Sstevel@tonic-gate } else if (strcmp(asinfo.as_behavior, "shutdown") == 0 ||
5722df1fe9cSrandyf strcmp(asinfo.as_behavior, "autowakeup") == 0) {
5737c478bd9Sstevel@tonic-gate info->pd_autoshutdown = asinfo.is_cpr_capable;
5747c478bd9Sstevel@tonic-gate } else {
5757c478bd9Sstevel@tonic-gate logerror("autoshutdown behavior \"%s\" unrecognized.",
5767c478bd9Sstevel@tonic-gate asinfo.as_behavior);
5777c478bd9Sstevel@tonic-gate info->pd_autoshutdown = 0;
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate if (info->pd_autoshutdown) {
5817c478bd9Sstevel@tonic-gate info->pd_idle_time = asinfo.as_idle;
5827c478bd9Sstevel@tonic-gate info->pd_start_time =
5837c478bd9Sstevel@tonic-gate (asinfo.as_sh * 60 + asinfo.as_sm) % DAYS_TO_MINS;
5847c478bd9Sstevel@tonic-gate info->pd_finish_time =
5857c478bd9Sstevel@tonic-gate (asinfo.as_fh * 60 + asinfo.as_fm) % DAYS_TO_MINS;
5867c478bd9Sstevel@tonic-gate info->pd_autoresume =
5877c478bd9Sstevel@tonic-gate (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0;
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown)
5902df1fe9cSrandyf ? 1 : 0;
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate #ifdef DEBUG
5937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, "
5942df1fe9cSrandyf "pd_autoresume = %d\n",
5952df1fe9cSrandyf autoshutdown_en, asinfo.as_idle, info->pd_autoresume);
5962df1fe9cSrandyf
5977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n",
5982df1fe9cSrandyf info->pd_start_time, info->pd_finish_time);
5997c478bd9Sstevel@tonic-gate #endif
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate got_sighup = 1;
6027c478bd9Sstevel@tonic-gate now = last_resume = time(NULL);
6037c478bd9Sstevel@tonic-gate hr_now = gethrtime();
6047c478bd9Sstevel@tonic-gate check_idleness(&now, &hr_now);
6057c478bd9Sstevel@tonic-gate check_shutdown(&now, &hr_now);
6067c478bd9Sstevel@tonic-gate set_alarm(now);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate static void
check_shutdown(time_t * now,hrtime_t * hr_now)6107c478bd9Sstevel@tonic-gate check_shutdown(time_t *now, hrtime_t *hr_now)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate int tod_fd = -1;
6137c478bd9Sstevel@tonic-gate int kbd, mouse, system, least_idle, idlecheck_time;
6147c478bd9Sstevel@tonic-gate int next_time;
6157c478bd9Sstevel@tonic-gate int s, f;
6167c478bd9Sstevel@tonic-gate struct tm tmp_time;
6177c478bd9Sstevel@tonic-gate time_t start_of_day, time_since_last_resume;
6187c478bd9Sstevel@tonic-gate time_t wakeup_time;
6197c478bd9Sstevel@tonic-gate extern long conskbd_idle_time(void);
6207c478bd9Sstevel@tonic-gate extern long consms_idle_time(void);
6217c478bd9Sstevel@tonic-gate static int warned_kbd, warned_ms; /* print error msg one time */
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate if (!autoshutdown_en) {
6247c478bd9Sstevel@tonic-gate shutdown_time = 0;
6257c478bd9Sstevel@tonic-gate return;
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate (void) localtime_r(now, &tmp_time);
6297c478bd9Sstevel@tonic-gate tmp_time.tm_sec = 0;
6307c478bd9Sstevel@tonic-gate tmp_time.tm_min = 0;
6317c478bd9Sstevel@tonic-gate tmp_time.tm_hour = 0;
6327c478bd9Sstevel@tonic-gate start_of_day = mktime(&tmp_time);
6337c478bd9Sstevel@tonic-gate s = start_of_day + info->pd_start_time * 60;
6347c478bd9Sstevel@tonic-gate f = start_of_day + info->pd_finish_time * 60;
6357c478bd9Sstevel@tonic-gate if ((s < f && *now >= s && *now < f) ||
6367c478bd9Sstevel@tonic-gate (s >= f && (*now < f || *now >= s))) {
6377c478bd9Sstevel@tonic-gate if ((mouse = (int)consms_idle_time()) < 0) {
6387c478bd9Sstevel@tonic-gate if (! warned_ms) {
6397c478bd9Sstevel@tonic-gate warned_ms = 1;
6407c478bd9Sstevel@tonic-gate logerror("powerd: failed to get "
6417c478bd9Sstevel@tonic-gate "idle time for console mouse");
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate return;
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate if ((kbd = (int)conskbd_idle_time()) < 0) {
6467c478bd9Sstevel@tonic-gate if (! warned_kbd) {
6477c478bd9Sstevel@tonic-gate warned_kbd = 1;
6487c478bd9Sstevel@tonic-gate logerror("powerd: failed to get "
6497c478bd9Sstevel@tonic-gate "idle time for console keyboard");
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate return;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate system = last_system_activity(hr_now);
6557c478bd9Sstevel@tonic-gate /* who is the last to go idle */
6567c478bd9Sstevel@tonic-gate least_idle = MIN(system, MIN(kbd, mouse));
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate * Calculate time_since_last_resume and the next_time
6607c478bd9Sstevel@tonic-gate * to auto suspend.
6617c478bd9Sstevel@tonic-gate */
6627c478bd9Sstevel@tonic-gate start_calc = 1;
6637c478bd9Sstevel@tonic-gate time_since_last_resume = time(NULL) - last_resume;
6647c478bd9Sstevel@tonic-gate next_time = info->pd_idle_time * 60 -
6652df1fe9cSrandyf MIN(least_idle, time_since_last_resume);
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate #ifdef DEBUG
6682df1fe9cSrandyf fprintf(stderr, " check_shutdown: next_time=%d\n", next_time);
6697c478bd9Sstevel@tonic-gate #endif
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate * If we have get the SIGTHAW signal at this point - our
6737c478bd9Sstevel@tonic-gate * calculation of time_since_last_resume is wrong so
6747c478bd9Sstevel@tonic-gate * - we need to recalculate.
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate while (start_calc == 0) {
6777c478bd9Sstevel@tonic-gate /* need to redo calculation */
6787c478bd9Sstevel@tonic-gate start_calc = 1;
6797c478bd9Sstevel@tonic-gate time_since_last_resume = time(NULL) - last_resume;
6807c478bd9Sstevel@tonic-gate next_time = info->pd_idle_time * 60 -
6812df1fe9cSrandyf MIN(least_idle, time_since_last_resume);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate * Only when everything else is idle, run the user's idlecheck
6867c478bd9Sstevel@tonic-gate * script.
6877c478bd9Sstevel@tonic-gate */
6887c478bd9Sstevel@tonic-gate if (next_time <= 0 && do_idlecheck) {
6897c478bd9Sstevel@tonic-gate got_sighup = 0;
6907c478bd9Sstevel@tonic-gate idlecheck_time = run_idlecheck();
6917c478bd9Sstevel@tonic-gate next_time = info->pd_idle_time * 60 -
6922df1fe9cSrandyf MIN(idlecheck_time, MIN(least_idle,
6932df1fe9cSrandyf time_since_last_resume));
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate * If we have caught SIGTHAW or SIGHUP, need to
6967c478bd9Sstevel@tonic-gate * recalculate.
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate while (start_calc == 0 || got_sighup == 1) {
6997c478bd9Sstevel@tonic-gate start_calc = 1;
7007c478bd9Sstevel@tonic-gate got_sighup = 0;
7017c478bd9Sstevel@tonic-gate idlecheck_time = run_idlecheck();
7027c478bd9Sstevel@tonic-gate time_since_last_resume = time(NULL) -
7032df1fe9cSrandyf last_resume;
7047c478bd9Sstevel@tonic-gate next_time = info->pd_idle_time * 60 -
7052df1fe9cSrandyf MIN(idlecheck_time, MIN(least_idle,
7062df1fe9cSrandyf time_since_last_resume));
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate if (next_time <= 0) {
7117c478bd9Sstevel@tonic-gate if (is_ok2shutdown(now)) {
7127c478bd9Sstevel@tonic-gate /*
7137c478bd9Sstevel@tonic-gate * Setup the autowakeup alarm. Clear it
7147c478bd9Sstevel@tonic-gate * right after poweroff, just in case if
7157c478bd9Sstevel@tonic-gate * shutdown doesn't go through.
7167c478bd9Sstevel@tonic-gate */
7177c478bd9Sstevel@tonic-gate if (info->pd_autoresume)
7187c478bd9Sstevel@tonic-gate tod_fd = open(TOD, O_RDWR);
7197c478bd9Sstevel@tonic-gate if (info->pd_autoresume && tod_fd != -1) {
7207c478bd9Sstevel@tonic-gate wakeup_time = (*now < f) ? f :
7212df1fe9cSrandyf (f + DAYS_TO_SECS);
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * A software fix for hardware
7247c478bd9Sstevel@tonic-gate * bug 1217415.
7257c478bd9Sstevel@tonic-gate */
7267c478bd9Sstevel@tonic-gate if ((wakeup_time - *now) < 180) {
7277c478bd9Sstevel@tonic-gate logerror(
7287c478bd9Sstevel@tonic-gate "Since autowakeup time is less than 3 minutes away, "
7297c478bd9Sstevel@tonic-gate "autoshutdown will not occur.");
7307c478bd9Sstevel@tonic-gate shutdown_time = *now + 180;
73180148899SSurya Prakki (void) close(tod_fd);
7327c478bd9Sstevel@tonic-gate return;
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate if (ioctl(tod_fd, TOD_SET_ALARM,
7352df1fe9cSrandyf &wakeup_time) == -1) {
7362df1fe9cSrandyf logerror("Unable to program TOD"
7372df1fe9cSrandyf " alarm for autowakeup.");
73880148899SSurya Prakki (void) close(tod_fd);
7397c478bd9Sstevel@tonic-gate return;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate (void) poweroff("Autoshutdown",
7447c478bd9Sstevel@tonic-gate autoshutdown_cmd);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate if (info->pd_autoresume && tod_fd != -1) {
7477c478bd9Sstevel@tonic-gate if (ioctl(tod_fd, TOD_CLEAR_ALARM,
7482df1fe9cSrandyf NULL) == -1)
7497c478bd9Sstevel@tonic-gate logerror("Unable to clear "
7507c478bd9Sstevel@tonic-gate "alarm in TOD device.");
75180148899SSurya Prakki (void) close(tod_fd);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate (void) time(now);
7557c478bd9Sstevel@tonic-gate /* wait at least 5 mins */
7567c478bd9Sstevel@tonic-gate shutdown_time = *now +
7572df1fe9cSrandyf ((info->pd_idle_time * 60) > 300 ?
7582df1fe9cSrandyf (info->pd_idle_time * 60) : 300);
7597c478bd9Sstevel@tonic-gate } else {
7607c478bd9Sstevel@tonic-gate /* wait 5 mins */
7617c478bd9Sstevel@tonic-gate shutdown_time = *now + 300;
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate } else
7647c478bd9Sstevel@tonic-gate shutdown_time = *now + next_time;
7657c478bd9Sstevel@tonic-gate } else if (s < f && *now >= f) {
7667c478bd9Sstevel@tonic-gate shutdown_time = s + DAYS_TO_SECS;
7677c478bd9Sstevel@tonic-gate } else
7687c478bd9Sstevel@tonic-gate shutdown_time = s;
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate static int
is_ok2shutdown(time_t * now)7727c478bd9Sstevel@tonic-gate is_ok2shutdown(time_t *now)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate int prom_fd = -1;
7757c478bd9Sstevel@tonic-gate char power_cycles_st[LLEN];
7767c478bd9Sstevel@tonic-gate char power_cycle_limit_st[LLEN];
7777c478bd9Sstevel@tonic-gate char system_board_date_st[LLEN];
7787c478bd9Sstevel@tonic-gate int power_cycles, power_cycle_limit, free_cycles, scaled_cycles;
7797c478bd9Sstevel@tonic-gate time_t life_began, life_passed;
7807c478bd9Sstevel@tonic-gate int no_power_cycles = 0;
7817c478bd9Sstevel@tonic-gate int no_system_board_date = 0;
7827c478bd9Sstevel@tonic-gate int ret = 1;
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate /* CONSTCOND */
7857c478bd9Sstevel@tonic-gate while (1) {
7867c478bd9Sstevel@tonic-gate if ((prom_fd = open(PROM, O_RDWR)) == -1 &&
7872df1fe9cSrandyf (errno == EAGAIN))
7882df1fe9cSrandyf continue;
7897c478bd9Sstevel@tonic-gate break;
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate /*
7937c478bd9Sstevel@tonic-gate * when #power-cycles property does not exist
7947c478bd9Sstevel@tonic-gate * power cycles are unlimited.
7957c478bd9Sstevel@tonic-gate */
7967c478bd9Sstevel@tonic-gate if (get_prom(prom_fd, options, "#power-cycles",
7977c478bd9Sstevel@tonic-gate power_cycles_st, sizeof (power_cycles_st)) == 0)
7987c478bd9Sstevel@tonic-gate goto ckdone;
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate if (get_prom(prom_fd, root, "power-cycle-limit",
8017c478bd9Sstevel@tonic-gate power_cycle_limit_st, sizeof (power_cycle_limit_st)) == 0) {
8027c478bd9Sstevel@tonic-gate power_cycle_limit = DEFAULT_POWER_CYCLE_LIMIT;
8037c478bd9Sstevel@tonic-gate } else {
8047c478bd9Sstevel@tonic-gate power_cycle_limit = atoi(power_cycle_limit_st);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate * Allow 10% of power_cycle_limit as free cycles.
8097c478bd9Sstevel@tonic-gate */
810c42872d4Smh free_cycles = power_cycle_limit / 10;
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate power_cycles = atoi(power_cycles_st);
8137c478bd9Sstevel@tonic-gate if (power_cycles < 0)
8147c478bd9Sstevel@tonic-gate no_power_cycles++;
8157c478bd9Sstevel@tonic-gate else if (power_cycles <= free_cycles)
8167c478bd9Sstevel@tonic-gate goto ckdone;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate if (no_power_cycles && log_power_cycles_error == 0) {
8197c478bd9Sstevel@tonic-gate logerror("Invalid PROM property \"#power-cycles\" was found.");
8207c478bd9Sstevel@tonic-gate log_power_cycles_error++;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate if (get_prom(prom_fd, options, "system-board-date",
8247c478bd9Sstevel@tonic-gate system_board_date_st, sizeof (system_board_date_st)) == 0) {
8257c478bd9Sstevel@tonic-gate no_system_board_date++;
8267c478bd9Sstevel@tonic-gate } else {
8277c478bd9Sstevel@tonic-gate life_began = strtol(system_board_date_st, (char **)NULL, 16);
8287c478bd9Sstevel@tonic-gate if (life_began > *now) {
8297c478bd9Sstevel@tonic-gate no_system_board_date++;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate if (no_system_board_date) {
8337c478bd9Sstevel@tonic-gate if (log_system_board_date_error == 0) {
8347c478bd9Sstevel@tonic-gate logerror("No or invalid PROM property "
8357c478bd9Sstevel@tonic-gate "\"system-board-date\" was found.");
8367c478bd9Sstevel@tonic-gate log_system_board_date_error++;
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate life_began = DEFAULT_SYSTEM_BOARD_DATE;
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate life_passed = *now - life_began;
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate * Since we don't keep the date that last free_cycle is ended, we
8457c478bd9Sstevel@tonic-gate * need to spread (power_cycle_limit - free_cycles) over the entire
8467c478bd9Sstevel@tonic-gate * 7-year life span instead of (lifetime - date free_cycles ended).
8477c478bd9Sstevel@tonic-gate */
848c42872d4Smh scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) *
8492df1fe9cSrandyf (power_cycle_limit - free_cycles));
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate if (no_power_cycles)
8527c478bd9Sstevel@tonic-gate goto ckdone;
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate #ifdef DEBUG
8557c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Actual power_cycles = %d\t"
8562df1fe9cSrandyf "Scaled power_cycles = %d\n", power_cycles, scaled_cycles);
8577c478bd9Sstevel@tonic-gate #endif
8587c478bd9Sstevel@tonic-gate if (power_cycles > scaled_cycles) {
8597c478bd9Sstevel@tonic-gate if (log_no_autoshutdown_warning == 0) {
8607c478bd9Sstevel@tonic-gate logerror("Automatic shutdown has been temporarily "
8617c478bd9Sstevel@tonic-gate "suspended in order to preserve the reliability "
8627c478bd9Sstevel@tonic-gate "of this system.");
8637c478bd9Sstevel@tonic-gate log_no_autoshutdown_warning++;
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate ret = 0;
8667c478bd9Sstevel@tonic-gate goto ckdone;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate ckdone:
8707c478bd9Sstevel@tonic-gate if (prom_fd != -1)
87180148899SSurya Prakki (void) close(prom_fd);
8727c478bd9Sstevel@tonic-gate return (ret);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate static void
check_idleness(time_t * now,hrtime_t * hr_now)8767c478bd9Sstevel@tonic-gate check_idleness(time_t *now, hrtime_t *hr_now)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate /*
8807c478bd9Sstevel@tonic-gate * Check idleness only when autoshutdown is enabled.
8817c478bd9Sstevel@tonic-gate */
8827c478bd9Sstevel@tonic-gate if (!autoshutdown_en) {
8837c478bd9Sstevel@tonic-gate checkidle_time = 0;
8847c478bd9Sstevel@tonic-gate return;
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate info->pd_ttychars_idle = check_tty(hr_now, asinfo.ttychars_thold);
8887c478bd9Sstevel@tonic-gate info->pd_loadaverage_idle =
8897c478bd9Sstevel@tonic-gate check_load_ave(hr_now, asinfo.loadaverage_thold);
8907c478bd9Sstevel@tonic-gate info->pd_diskreads_idle = check_disks(hr_now, asinfo.diskreads_thold);
8917c478bd9Sstevel@tonic-gate info->pd_nfsreqs_idle = check_nfs(hr_now, asinfo.nfsreqs_thold);
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate #ifdef DEBUG
8947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Idle ttychars for %d secs.\n",
8952df1fe9cSrandyf info->pd_ttychars_idle);
8967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Idle loadaverage for %d secs.\n",
8972df1fe9cSrandyf info->pd_loadaverage_idle);
8987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Idle diskreads for %d secs.\n",
8992df1fe9cSrandyf info->pd_diskreads_idle);
9007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Idle nfsreqs for %d secs.\n",
9012df1fe9cSrandyf info->pd_nfsreqs_idle);
9027c478bd9Sstevel@tonic-gate #endif
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate checkidle_time = *now + IDLECHK_INTERVAL;
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate static int
last_system_activity(hrtime_t * hr_now)9087c478bd9Sstevel@tonic-gate last_system_activity(hrtime_t *hr_now)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate int act_idle, latest;
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate latest = info->pd_idle_time * 60;
9137c478bd9Sstevel@tonic-gate act_idle = last_tty_activity(hr_now, asinfo.ttychars_thold);
9147c478bd9Sstevel@tonic-gate latest = MIN(latest, act_idle);
9157c478bd9Sstevel@tonic-gate act_idle = last_load_ave_activity(hr_now);
9167c478bd9Sstevel@tonic-gate latest = MIN(latest, act_idle);
9177c478bd9Sstevel@tonic-gate act_idle = last_disk_activity(hr_now, asinfo.diskreads_thold);
9187c478bd9Sstevel@tonic-gate latest = MIN(latest, act_idle);
9197c478bd9Sstevel@tonic-gate act_idle = last_nfs_activity(hr_now, asinfo.nfsreqs_thold);
9207c478bd9Sstevel@tonic-gate latest = MIN(latest, act_idle);
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate return (latest);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate static int
run_idlecheck()9267c478bd9Sstevel@tonic-gate run_idlecheck()
9277c478bd9Sstevel@tonic-gate {
9287c478bd9Sstevel@tonic-gate char pm_variable[LLEN];
9297c478bd9Sstevel@tonic-gate char *cp;
9307c478bd9Sstevel@tonic-gate int status;
9317c478bd9Sstevel@tonic-gate pid_t child;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate /*
9347c478bd9Sstevel@tonic-gate * Reap any child process which has been left over.
9357c478bd9Sstevel@tonic-gate */
9362df1fe9cSrandyf while (waitpid((pid_t)-1, &status, WNOHANG) > 0)
9372df1fe9cSrandyf ;
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate * Execute the user's idlecheck script and set variable PM_IDLETIME.
9417c478bd9Sstevel@tonic-gate * Returned exit value is the idle time in minutes.
9427c478bd9Sstevel@tonic-gate */
9437c478bd9Sstevel@tonic-gate if ((child = fork1()) == 0) {
9447c478bd9Sstevel@tonic-gate (void) sprintf(pm_variable, "PM_IDLETIME=%d",
9452df1fe9cSrandyf info->pd_idle_time);
9467c478bd9Sstevel@tonic-gate (void) putenv(pm_variable);
9477c478bd9Sstevel@tonic-gate cp = strrchr(asinfo.idlecheck_path, '/');
9487c478bd9Sstevel@tonic-gate if (cp == NULL)
9497c478bd9Sstevel@tonic-gate cp = asinfo.idlecheck_path;
9507c478bd9Sstevel@tonic-gate else
9517c478bd9Sstevel@tonic-gate cp++;
9527c478bd9Sstevel@tonic-gate (void) execl(asinfo.idlecheck_path, cp, NULL);
9537c478bd9Sstevel@tonic-gate exit(-1);
9547c478bd9Sstevel@tonic-gate } else if (child == -1) {
9557c478bd9Sstevel@tonic-gate return (info->pd_idle_time * 60);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * Wait until the idlecheck program completes.
9607c478bd9Sstevel@tonic-gate */
9617c478bd9Sstevel@tonic-gate if (waitpid(child, &status, 0) != child) {
9627c478bd9Sstevel@tonic-gate /*
9637c478bd9Sstevel@tonic-gate * We get here if the calling process gets a signal.
9647c478bd9Sstevel@tonic-gate */
9657c478bd9Sstevel@tonic-gate return (info->pd_idle_time * 60);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate if (WEXITSTATUS(status) < 0) {
9697c478bd9Sstevel@tonic-gate return (info->pd_idle_time * 60);
9707c478bd9Sstevel@tonic-gate } else {
9717c478bd9Sstevel@tonic-gate return (WEXITSTATUS(status) * 60);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate static void
set_alarm(time_t now)9767c478bd9Sstevel@tonic-gate set_alarm(time_t now)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate time_t itime, stime, next_time, max_time;
9797c478bd9Sstevel@tonic-gate int next_alarm;
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate max_time = MAX(checkidle_time, shutdown_time);
9827c478bd9Sstevel@tonic-gate if (max_time == 0) {
9837c478bd9Sstevel@tonic-gate (void) alarm(0);
9847c478bd9Sstevel@tonic-gate return;
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate itime = (checkidle_time == 0) ? max_time : checkidle_time;
9877c478bd9Sstevel@tonic-gate stime = (shutdown_time == 0) ? max_time : shutdown_time;
9887c478bd9Sstevel@tonic-gate next_time = MIN(itime, stime);
9897c478bd9Sstevel@tonic-gate next_alarm = (next_time <= now) ? 1 : (next_time - now);
9907c478bd9Sstevel@tonic-gate (void) alarm(next_alarm);
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate #ifdef DEBUG
9937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Currently @ %s", ctime(&now));
9947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Checkidle in %d secs\n", checkidle_time - now);
9957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Shutdown in %d secs\n", shutdown_time - now);
9967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Next alarm goes off in %d secs\n", next_alarm);
9977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "************************************\n");
9987c478bd9Sstevel@tonic-gate #endif
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate
10017c478bd9Sstevel@tonic-gate static int
poweroff(const char * msg,char ** cmd_argv)1002c42872d4Smh poweroff(const char *msg, char **cmd_argv)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate struct stat statbuf;
10057c478bd9Sstevel@tonic-gate pid_t pid, child;
10067c478bd9Sstevel@tonic-gate struct passwd *pwd;
10077c478bd9Sstevel@tonic-gate char *home, *user;
10087c478bd9Sstevel@tonic-gate char ehome[] = "HOME=";
10097c478bd9Sstevel@tonic-gate char euser[] = "LOGNAME=";
10107c478bd9Sstevel@tonic-gate int status;
10117c478bd9Sstevel@tonic-gate char **ca;
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate if (mutex_trylock(&poweroff_mutex) != 0)
10147c478bd9Sstevel@tonic-gate return (0);
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gate if (stat("/dev/console", &statbuf) == -1 ||
10177c478bd9Sstevel@tonic-gate (pwd = getpwuid(statbuf.st_uid)) == NULL) {
101880148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10197c478bd9Sstevel@tonic-gate return (1);
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate if (msg)
10237c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, msg);
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate if (*cmd_argv == NULL) {
10267c478bd9Sstevel@tonic-gate logerror("No command to run.");
102780148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10287c478bd9Sstevel@tonic-gate return (1);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate home = malloc(strlen(pwd->pw_dir) + sizeof (ehome));
10327c478bd9Sstevel@tonic-gate user = malloc(strlen(pwd->pw_name) + sizeof (euser));
10337c478bd9Sstevel@tonic-gate if (home == NULL || user == NULL) {
10347c478bd9Sstevel@tonic-gate free(home);
10357c478bd9Sstevel@tonic-gate free(user);
10367c478bd9Sstevel@tonic-gate logerror("No memory.");
103780148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10387c478bd9Sstevel@tonic-gate return (1);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate (void) strcpy(home, ehome);
10417c478bd9Sstevel@tonic-gate (void) strcat(home, pwd->pw_dir);
10427c478bd9Sstevel@tonic-gate (void) strcpy(user, euser);
10437c478bd9Sstevel@tonic-gate (void) strcat(user, pwd->pw_name);
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate * Need to simulate the user enviroment, minimaly set HOME, and USER.
10477c478bd9Sstevel@tonic-gate */
10487c478bd9Sstevel@tonic-gate if ((child = fork1()) == 0) {
10497c478bd9Sstevel@tonic-gate (void) putenv(home);
10507c478bd9Sstevel@tonic-gate (void) putenv(user);
10517c478bd9Sstevel@tonic-gate (void) setgid(pwd->pw_gid);
10527c478bd9Sstevel@tonic-gate (void) setuid(pwd->pw_uid);
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate /*
10557c478bd9Sstevel@tonic-gate * check for shutdown flag and set environment
10567c478bd9Sstevel@tonic-gate */
10577c478bd9Sstevel@tonic-gate for (ca = cmd_argv; *ca; ca++) {
10587c478bd9Sstevel@tonic-gate if (strcmp("-h", *ca) == 0) {
10597c478bd9Sstevel@tonic-gate (void) putenv("SYSSUSPENDDODEFAULT=");
10607c478bd9Sstevel@tonic-gate break;
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate (void) execv(cmd_argv[0], cmd_argv);
10657c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
10667c478bd9Sstevel@tonic-gate } else {
10677c478bd9Sstevel@tonic-gate free(home);
10687c478bd9Sstevel@tonic-gate free(user);
10697c478bd9Sstevel@tonic-gate if (child == -1) {
107080148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10717c478bd9Sstevel@tonic-gate return (1);
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate pid = 0;
10757c478bd9Sstevel@tonic-gate while (pid != child)
10767c478bd9Sstevel@tonic-gate pid = wait(&status);
10777c478bd9Sstevel@tonic-gate if (WEXITSTATUS(status)) {
10787c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "Failed to exec \"%s\".", cmd_argv[0]);
107980148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10807c478bd9Sstevel@tonic-gate return (1);
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate
108380148899SSurya Prakki (void) mutex_unlock(&poweroff_mutex);
10847c478bd9Sstevel@tonic-gate return (0);
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate #define PBUFSIZE 256
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate * Gets the value of a prom property at either root or options node. It
10917c478bd9Sstevel@tonic-gate * returns 1 if it is successful, otherwise it returns 0 .
10927c478bd9Sstevel@tonic-gate */
10937c478bd9Sstevel@tonic-gate static int
get_prom(int prom_fd,prom_node_t node_name,char * property_name,char * property_value,size_t len)10947c478bd9Sstevel@tonic-gate get_prom(int prom_fd, prom_node_t node_name,
109513c646d3SAlexander Eremin char *property_name, char *property_value, size_t len)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate union {
10987c478bd9Sstevel@tonic-gate char buf[PBUFSIZE + sizeof (uint_t)];
10997c478bd9Sstevel@tonic-gate struct openpromio opp;
11007c478bd9Sstevel@tonic-gate } oppbuf;
11017c478bd9Sstevel@tonic-gate register struct openpromio *opp = &(oppbuf.opp);
11027c478bd9Sstevel@tonic-gate int got_it = 0;
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate if (prom_fd == -1) {
11057c478bd9Sstevel@tonic-gate return (0);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate switch (node_name) {
11097c478bd9Sstevel@tonic-gate case root:
1110*b172429eSMarco van Wieringen (void) memset(oppbuf.buf, 0, PBUFSIZE);
11117c478bd9Sstevel@tonic-gate opp->oprom_size = PBUFSIZE;
11127c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNEXT, opp) < 0) {
11137c478bd9Sstevel@tonic-gate return (0);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate * Passing null string will give us the first property.
11187c478bd9Sstevel@tonic-gate */
1119*b172429eSMarco van Wieringen (void) memset(oppbuf.buf, 0, PBUFSIZE);
11207c478bd9Sstevel@tonic-gate do {
11217c478bd9Sstevel@tonic-gate opp->oprom_size = PBUFSIZE;
11227c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) {
11237c478bd9Sstevel@tonic-gate return (0);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate if (strcmp(opp->oprom_array, property_name) == 0) {
11267c478bd9Sstevel@tonic-gate got_it++;
11277c478bd9Sstevel@tonic-gate break;
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate } while (opp->oprom_size > 0);
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate if (!got_it) {
11327c478bd9Sstevel@tonic-gate return (0);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate if (got_it && property_value == NULL) {
11357c478bd9Sstevel@tonic-gate return (1);
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate opp->oprom_size = PBUFSIZE;
11387c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) {
11397c478bd9Sstevel@tonic-gate return (0);
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate if (opp->oprom_size == 0) {
11427c478bd9Sstevel@tonic-gate *property_value = '\0';
11437c478bd9Sstevel@tonic-gate } else {
11447c478bd9Sstevel@tonic-gate estrcpy(property_value, opp->oprom_array, len);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate break;
11477c478bd9Sstevel@tonic-gate case options:
11487c478bd9Sstevel@tonic-gate estrcpy(opp->oprom_array, property_name, PBUFSIZE);
11497c478bd9Sstevel@tonic-gate opp->oprom_size = PBUFSIZE;
11507c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
11517c478bd9Sstevel@tonic-gate return (0);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate if (opp->oprom_size == 0) {
11547c478bd9Sstevel@tonic-gate return (0);
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate if (property_value != NULL) {
11577c478bd9Sstevel@tonic-gate estrcpy(property_value, opp->oprom_array, len);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate break;
11607c478bd9Sstevel@tonic-gate default:
11617c478bd9Sstevel@tonic-gate logerror("Only root node and options node are supported.\n");
11627c478bd9Sstevel@tonic-gate return (0);
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate
11657c478bd9Sstevel@tonic-gate return (1);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate #define isspace(ch) ((ch) == ' ' || (ch) == '\t')
11697c478bd9Sstevel@tonic-gate #define iseol(ch) ((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate /*ARGSUSED*/
117245057a1aSToomas Soome static void *
power_button_monitor(void * arg)11737c478bd9Sstevel@tonic-gate power_button_monitor(void *arg)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate struct pollfd pfd;
1176d2ec54f7Sphitran int events, ret;
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) {
11797c478bd9Sstevel@tonic-gate logerror("Failed to monitor the power button.");
11807c478bd9Sstevel@tonic-gate thr_exit((void *) 0);
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate pfd.fd = pb_fd;
11847c478bd9Sstevel@tonic-gate pfd.events = POLLIN;
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate /*CONSTCOND*/
11877c478bd9Sstevel@tonic-gate while (1) {
11887c478bd9Sstevel@tonic-gate if (poll(&pfd, 1, INFTIM) == -1) {
11897c478bd9Sstevel@tonic-gate logerror("Failed to poll for power button events.");
11907c478bd9Sstevel@tonic-gate thr_exit((void *) 0);
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate if (!(pfd.revents & POLLIN))
11947c478bd9Sstevel@tonic-gate continue;
11957c478bd9Sstevel@tonic-gate
1196d2ec54f7Sphitran /*
1197d2ec54f7Sphitran * Monitor the power button, but only take action if
1198d2ec54f7Sphitran * gnome-power-manager is not running.
1199d2ec54f7Sphitran *
1200d2ec54f7Sphitran * ret greater than 0 means could not find process.
1201d2ec54f7Sphitran */
12023f14f381SPhi Tran ret = system("/usr/bin/pgrep -fx gnome-power-manager");
1203d2ec54f7Sphitran
12047c478bd9Sstevel@tonic-gate if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
12057c478bd9Sstevel@tonic-gate logerror("Failed to get power button events.");
12067c478bd9Sstevel@tonic-gate thr_exit((void *) 0);
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate
1209d2ec54f7Sphitran if ((ret > 0) && (events & PB_BUTTON_PRESS) &&
12107c478bd9Sstevel@tonic-gate (poweroff(NULL, power_button_cmd) != 0)) {
12117c478bd9Sstevel@tonic-gate logerror("Power button is pressed, powering "
12127c478bd9Sstevel@tonic-gate "down the system!");
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate /*
12157c478bd9Sstevel@tonic-gate * Send SIGPWR signal to the init process to
12167c478bd9Sstevel@tonic-gate * shut down the system.
12177c478bd9Sstevel@tonic-gate */
12187c478bd9Sstevel@tonic-gate if (kill(1, SIGPWR) == -1)
12197c478bd9Sstevel@tonic-gate (void) uadmin(A_SHUTDOWN, AD_POWEROFF, 0);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate /*
12237c478bd9Sstevel@tonic-gate * Clear any power button event that has happened
12247c478bd9Sstevel@tonic-gate * meanwhile we were busy processing the last one.
12257c478bd9Sstevel@tonic-gate */
12267c478bd9Sstevel@tonic-gate if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) {
12277c478bd9Sstevel@tonic-gate logerror("Failed to get power button events.");
12287c478bd9Sstevel@tonic-gate thr_exit((void *) 0);
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate }
123145057a1aSToomas Soome return (NULL);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate static void
do_attach(void)12357c478bd9Sstevel@tonic-gate do_attach(void)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate if (read_cpr_config() < 0)
12387c478bd9Sstevel@tonic-gate return;
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate /*
12417c478bd9Sstevel@tonic-gate * If autopm behavior is explicitly enabled for energystar-v2, or
12427c478bd9Sstevel@tonic-gate * set to default for energystar-v3, create a new thread to attach
12437c478bd9Sstevel@tonic-gate * all devices.
12447c478bd9Sstevel@tonic-gate */
12457c478bd9Sstevel@tonic-gate estar_v3_prop = asinfo.is_autopm_default;
12467c478bd9Sstevel@tonic-gate if ((strcmp(asinfo.apm_behavior, "enable") == 0) ||
12477c478bd9Sstevel@tonic-gate (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) {
12482df1fe9cSrandyf if (powerd_debug)
12492df1fe9cSrandyf logerror("powerd starting device attach thread.");
12503f77e798SToomas Soome if (thr_create(NULL, 0, attach_devices, NULL,
12517c478bd9Sstevel@tonic-gate THR_DAEMON, NULL) != 0) {
12527c478bd9Sstevel@tonic-gate logerror("Unable to create thread to attach devices.");
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate }
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12587c478bd9Sstevel@tonic-gate static void *
attach_devices(void * arg)12597c478bd9Sstevel@tonic-gate attach_devices(void *arg)
12607c478bd9Sstevel@tonic-gate {
12617c478bd9Sstevel@tonic-gate di_node_t root_node;
12627c478bd9Sstevel@tonic-gate
126380148899SSurya Prakki (void) sleep(60); /* let booting finish first */
12647c478bd9Sstevel@tonic-gate
12657c478bd9Sstevel@tonic-gate if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) {
12667c478bd9Sstevel@tonic-gate logerror("Failed to attach devices.");
12677c478bd9Sstevel@tonic-gate return (NULL);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate di_fini(root_node);
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate * Unload all the modules.
12737c478bd9Sstevel@tonic-gate */
12747c478bd9Sstevel@tonic-gate (void) modctl(MODUNLOAD, 0);
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate return (NULL);
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate /*
12817c478bd9Sstevel@tonic-gate * Create a file which will contain our pid. Pmconfig will check this file
12827c478bd9Sstevel@tonic-gate * to see if we are running and can use the pid to signal us. Returns the
12837c478bd9Sstevel@tonic-gate * file descriptor if successful, -1 otherwise.
12847c478bd9Sstevel@tonic-gate *
12857c478bd9Sstevel@tonic-gate * Note: Deal with attempt to launch multiple instances and also with existence
12867c478bd9Sstevel@tonic-gate * of an obsolete pid file caused by an earlier abort.
12877c478bd9Sstevel@tonic-gate */
12887c478bd9Sstevel@tonic-gate static int
open_pidfile(char * me)12897c478bd9Sstevel@tonic-gate open_pidfile(char *me)
12907c478bd9Sstevel@tonic-gate {
12917c478bd9Sstevel@tonic-gate int fd;
1292c42872d4Smh const char *e1 = "%s: Cannot open pid file for read: ";
1293c42872d4Smh const char *e2 = "%s: Cannot unlink obsolete pid file: ";
1294c3a64150SMargot Miller const char *e3 = "%s: Either another daemon is running or the"
1295c3a64150SMargot Miller " process is defunct (pid %d). \n";
1296c3a64150SMargot Miller const char *e4 = "%s: Cannot create pid file: ";
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate again:
12997c478bd9Sstevel@tonic-gate if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) {
13007c478bd9Sstevel@tonic-gate if (errno == EEXIST) {
13017c478bd9Sstevel@tonic-gate FILE *fp;
13027c478bd9Sstevel@tonic-gate pid_t pid;
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate if ((fp = fopen(pidpath, "r")) == NULL) {
13057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, e1, me);
13067c478bd9Sstevel@tonic-gate perror(NULL);
13077c478bd9Sstevel@tonic-gate return (-1);
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate
13107c478bd9Sstevel@tonic-gate /* Read the pid */
13117c478bd9Sstevel@tonic-gate pid = (pid_t)-1;
13127c478bd9Sstevel@tonic-gate (void) fscanf(fp, "%ld", &pid);
13137c478bd9Sstevel@tonic-gate (void) fclose(fp);
13147c478bd9Sstevel@tonic-gate if (pid == -1) {
13157c478bd9Sstevel@tonic-gate if (unlink(pidpath) == -1) {
13167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, e2, me);
13177c478bd9Sstevel@tonic-gate perror(NULL);
13187c478bd9Sstevel@tonic-gate return (-1);
13197c478bd9Sstevel@tonic-gate } else /* try without corrupted file */
13207c478bd9Sstevel@tonic-gate goto again;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate
1323c3a64150SMargot Miller /* Is pid for a running process */
1324c3a64150SMargot Miller if (kill(pid, 0) == -1) {
1325c3a64150SMargot Miller if (errno == ESRCH) {
13267c478bd9Sstevel@tonic-gate if (unlink(pidpath) == -1) {
13277c478bd9Sstevel@tonic-gate (void) fprintf(stderr, e2, me);
13287c478bd9Sstevel@tonic-gate perror(NULL);
13297c478bd9Sstevel@tonic-gate return (-1);
13307c478bd9Sstevel@tonic-gate } else /* try without obsolete file */
13317c478bd9Sstevel@tonic-gate goto again;
13327c478bd9Sstevel@tonic-gate }
1333c3a64150SMargot Miller } else { /* powerd deamon still running or defunct */
13347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, e3, me, pid);
13357c478bd9Sstevel@tonic-gate return (-1);
13367c478bd9Sstevel@tonic-gate }
1337c3a64150SMargot Miller
13387c478bd9Sstevel@tonic-gate } else { /* create failure not due to existing file */
1339c3a64150SMargot Miller (void) fprintf(stderr, e4, me);
13407c478bd9Sstevel@tonic-gate perror(NULL);
13417c478bd9Sstevel@tonic-gate return (-1);
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate }
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate (void) fchown(fd, (uid_t)-1, (gid_t)0);
13467c478bd9Sstevel@tonic-gate return (fd);
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate /*
13507c478bd9Sstevel@tonic-gate * Write a pid to the pid file. Report errors to syslog.
13517c478bd9Sstevel@tonic-gate *
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate static int
write_pidfile(int fd,pid_t pid)13547c478bd9Sstevel@tonic-gate write_pidfile(int fd, pid_t pid)
13557c478bd9Sstevel@tonic-gate {
13567c478bd9Sstevel@tonic-gate int len;
13577c478bd9Sstevel@tonic-gate int rc = 0; /* assume success */
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate len = sprintf(scratch, "%ld\n", pid);
13607c478bd9Sstevel@tonic-gate if (write(fd, scratch, len) != len) {
13617c478bd9Sstevel@tonic-gate logerror("Cannot write pid file: %s", strerror(errno));
13627c478bd9Sstevel@tonic-gate rc = -1;
13637c478bd9Sstevel@tonic-gate }
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate return (rc);
13667c478bd9Sstevel@tonic-gate }
1367