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