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