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