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 }