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 2014, 2015 Shruti V Sampat <shrutisampat@gmail.com>
  23  */
  24 
  25 /*
  26  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  31 /*        All Rights Reserved   */
  32 
  33 /*
  34  * Portions of such source code were derived from Berkeley 4.3 BSD
  35  * under license from the Regents of the University of California.
  36  */
  37 
  38 /*
  39  * utmpd        - utmp daemon
  40  *
  41  *              This program receives requests from  pututxline(3)
  42  *              via a named pipe to watch the process to make sure it cleans up
  43  *              its utmpx entry on termination.
  44  *              The program keeps a list of procs
  45  *              and uses poll() on their /proc files to detect termination.
  46  *              Also the  program periodically scans the /etc/utmpx file for
  47  *              processes that aren't in the table so they can be watched.
  48  *
  49  *              If utmpd doesn't hear back over the pipe from pututline(3) that
  50  *              the process has removed its entry it cleans the entry when the
  51  *              the process terminates.
  52  *              The AT&T Copyright above is there since we borrowed the pipe
  53  *              mechanism from init(1m).
  54  */
  55 
  56 
  57 #include        <sys/types.h>
  58 #include        <signal.h>
  59 #include        <stdio.h>
  60 #include        <stdio_ext.h>
  61 #include        <unistd.h>
  62 #include        <utmpx.h>
  63 #include        <errno.h>
  64 #include        <termio.h>
  65 #include        <sys/termios.h>
  66 #include        <sys/tty.h>
  67 #include        <ctype.h>
  68 #include        <sys/stat.h>
  69 #include        <sys/statvfs.h>
  70 #include        <fcntl.h>
  71 #include        <time.h>
  72 #include        <sys/stropts.h>
  73 #include        <wait.h>
  74 #include        <syslog.h>
  75 #include        <stdlib.h>
  76 #include        <string.h>
  77 #include        <poll.h>
  78 #include        <deflt.h>
  79 #include        <procfs.h>
  80 #include        <sys/resource.h>
  81 #include        <limits.h>
  82 
  83 #define dprintf(x)      if (Debug) (void) printf x
  84 
  85 /*
  86  * Memory allocation keyed off MAX_FDS
  87  */
  88 #define MAX_FDS         4064    /* Maximum # file descriptors */
  89 #define EXTRA_MARGIN    32      /* Allocate this many more FDS over Max_Fds */
  90 /*
  91  * MAX_POLLNV & RESETS - paranoia to cover an error case that might not exist
  92  */
  93 #define MAX_POLL_ERRS   1024    /* Count of bad errors */
  94 #define MAX_RESETS      1024    /* Maximum times to reload tables */
  95 #define POLL_TIMEOUT    300     /* Default Timeout for poll() in seconds */
  96 #define CLEANIT         1       /* Used by rem_pid() */
  97 #define DONT_CLEAN      0       /* Used by rem_pid() */
  98 #define UTMP_DEFAULT    "/etc/default/utmpd"
  99 #define WARN_TIME       3600    /* seconds between utmp checks */
 100 #define WTMPX_UFREQ     60      /* seconds between updating WTMPX's atime */
 101 
 102 
 103 /*
 104  * The pidrec structure describes the data shipped down the pipe to
 105  * us from the pututxline() library in
 106  * lib/libc/port/gen/getutx.c
 107  */
 108 
 109 /*
 110  * pd_type's
 111  */
 112 #define ADDPID  1
 113 #define REMPID  2
 114 
 115 struct  pidrec {
 116         int     pd_type;                /* Command type */
 117         pid_t   pd_pid;                 /* pid to add or remove */
 118 };
 119 
 120 
 121 /*
 122  * Since this program uses poll(2) and poll takes an array of file descriptors
 123  * as an argument we maintain our data in tables.
 124  * One table is the file descriptor array for poll, another parallel
 125  * array is a table which contains the process ID of the corresponding
 126  * open fd.  These tables are kept sorted by process ID for quick lookups.
 127  */
 128 
 129 struct  pidentry {
 130         pid_t   pl_pid;                 /* pid to watch for */
 131         int     pl_status;              /* Exit status of proc */
 132 };
 133 
 134 static struct pidentry *pidtable = NULL;
 135 
 136 static pollfd_t *fdtable = NULL;
 137 
 138 static int      pidcnt = 0;             /* Number of procs being watched */
 139 static char     *prog_name;             /* To save the invocation name away */
 140 static char     *UTMPPIPE_DIR = "/var/run";
 141 static char     *UTMPPIPE = "/var/run/utmppipe";
 142 static int      Pfd = -1;               /* File descriptor of named pipe */
 143 static int      Poll_timeout = POLL_TIMEOUT;
 144 static int      WTMPXfd = -1;           /* File descriptor of WTMPX_FILE */
 145 static int      WTMPX_ufreq = WTMPX_UFREQ;
 146 static int      Debug = 0;              /* Set by command line argument */
 147 static int      Max_fds         = MAX_FDS;
 148 
 149 /*
 150  * This program has three main components plus utilities and debug routines
 151  *      Receiver - receives the process ID or process for us to watch.
 152  *                 (Uses a named pipe to get messages)
 153  *      Watcher  - Use poll(2) to watch for processes to die so they
 154  *                 can be cleaned up (get marked as DEAD_PROCESS)
 155  *      Scanner  - periodically scans the utmpx file for stale entries
 156  *                 or live entries that we don't know about.
 157  */
 158 
 159 static int wait_for_pids();     /* Watcher - uses poll */
 160 static void scan_utmps();       /* Scanner, reads utmpx file */
 161 static void drain_pipe();       /* Receiver - reads mesgs over UTMPPIPE */
 162 static void setup_pipe();       /* For setting up receiver */
 163 
 164 static void add_pid();          /* Adds a process to the table */
 165 static void rem_pid();          /* Removes a process from the table */
 166 static int find_pid();          /* Finds a process in the table */
 167 static int proc_to_fd();        /* Takes a pid and returns an fd for its proc */
 168 static void load_tables();      /* Loads up the tables the first time around */
 169 static int pidcmp();            /* For sorting pids */
 170 
 171 static void clean_entry();      /* Removes entry from our table and calls ... */
 172 static void clean_utmpx_ent();  /* Cleans a utmpx entry */
 173 
 174 static void fatal() __NORETURN; /* Prints error message and calls exit */
 175 static void nonfatal();         /* Prints error message */
 176 static void print_tables();     /* Prints out internal tables for Debug */
 177 static int proc_is_alive(pid_t pid);    /* Check if a process is alive */
 178 static void warn_utmp(void);
 179 
 180 /* Validate defaults from file and assign */
 181 static int validate_default(char *defp, int *flag);
 182 
 183 /*
 184  * main()  - Main does basic setup and calls wait_for_pids() to do the work
 185  */
 186 
 187 int
 188 main(int argc, char *argv[])
 189 {
 190         char *defp;
 191         struct rlimit rlim;
 192         int i;
 193         time_t curtime, now;
 194         char msg[256];
 195 
 196         prog_name = argv[0];                    /* Save invocation name */
 197 
 198         if (getuid() != 0)  {
 199                 (void) fprintf(stderr,
 200                     "You must be root to run this program\n");
 201                 fatal("You must be root to run this program");
 202         }
 203 
 204         if (argc > 1) {
 205                 if ((argc == 2 && (int)strlen(argv[1]) >= 2) &&
 206                     (argv[1][0] == '-' && argv[1][1] == 'd')) {
 207                         Debug = 1;
 208                 } else {
 209                         (void) fprintf(stderr,
 210                             "%s: Wrong number of arguments\n", prog_name);
 211                         (void) fprintf(stderr,
 212                             "Usage: %s [-debug]\n", prog_name);
 213                         exit(2);
 214                 }
 215         }
 216 
 217         /*
 218          * Read defaults file for poll timeout, WTMPX update frequency
 219          * and maximum number of processes to monitor.
 220          */
 221         if (defopen(UTMP_DEFAULT) == 0) {
 222                 if ((defp = defread("SCAN_PERIOD=")) != NULL)
 223                         if (validate_default(defp, &Poll_timeout) == -1) {
 224                                 (void) snprintf(msg, sizeof (msg), "SCAN_PERIOD"
 225                                     " should be a positive integer, found %s",
 226                                     defp);
 227                                 nonfatal(msg);
 228                         }
 229                 dprintf(("Poll timeout set to %d\n", Poll_timeout));
 230 
 231                 if ((defp = defread("WTMPX_UPDATE_FREQ=")) != NULL)
 232                         if (validate_default(defp, &WTMPX_ufreq) == -1) {
 233                                 (void) snprintf(msg, sizeof (msg),
 234                                     "WTMPX_UPDATE_FREQ should be a positive "
 235                                     "integer, found %s", defp);
 236                                 nonfatal(msg);
 237                         }
 238                 dprintf(("WTMPX update frequency set to %d\n", WTMPX_ufreq));
 239 
 240                 /*
 241                  * Paranoia - if polling on large number of FDs is expensive /
 242                  * buggy the number can be set lower in the field.
 243                  */
 244                 if ((defp = defread("MAX_FDS=")) != NULL)
 245                         if (validate_default(defp, &Max_fds) == -1) {
 246                                 (void) snprintf(msg, sizeof (msg), "MAX_FDS "
 247                                     "should be a positive integer, found %s",
 248                                     defp);
 249                                 nonfatal(msg);
 250                         }
 251                 dprintf(("Max fds set to %d\n", Max_fds));
 252                 (void) defopen((char *)NULL);
 253         }
 254 
 255         if (Debug == 0) {
 256                 /*
 257                  * Daemonize ourselves
 258                  */
 259                 if (fork()) {
 260                         exit(0);
 261                 }
 262                 (void) close(0);
 263                 (void) close(1);
 264                 (void) close(2);
 265                 /*
 266                  * We open these to avoid accidentally writing to a proc file
 267                  */
 268                 (void) open("/dev/null", O_RDONLY);
 269                 (void) open("/dev/null", O_WRONLY);
 270                 (void) open("/dev/null", O_WRONLY);
 271                 (void) setsid();                /* release process from tty */
 272         }
 273 
 274         openlog(prog_name, LOG_PID, LOG_DAEMON);        /* For error messages */
 275         warn_utmp();    /* check to see if utmp came back by accident */
 276 
 277         /*
 278          * Allocate the pidtable and fdtable.  An earlier version did
 279          * this as we go, but this is simpler.
 280          */
 281         if ((pidtable = malloc(Max_fds * sizeof (struct pidentry))) == NULL)
 282                 fatal("Malloc failed");
 283         if ((fdtable = malloc(Max_fds * sizeof (pollfd_t))) == NULL)
 284                 fatal("Malloc failed");
 285 
 286         /*
 287          * Up the limit on FDs
 288          */
 289         if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
 290                 rlim.rlim_cur = Max_fds + EXTRA_MARGIN + 1;
 291                 rlim.rlim_max = Max_fds + EXTRA_MARGIN + 1;
 292                 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
 293                         fatal("Out of File Descriptors");
 294                 }
 295         } else
 296                 fatal("getrlimit returned failure");
 297 
 298         (void) enable_extended_FILE_stdio(-1, -1);
 299 
 300         if ((WTMPXfd = open(WTMPX_FILE, O_RDONLY)) < 0)
 301                 nonfatal("WARNING: unable to open " WTMPX_FILE " for update.");
 302 
 303         /*
 304          * Loop here scanning the utmpx file and waiting for processes
 305          * to terminate.  Most of the activity is directed out of wait_for_pids.
 306          * If wait_for_pids fails we reload the table and try again.
 307          */
 308 
 309         curtime = time(NULL);
 310         dprintf(("utmp warning timer set to %d seconds\n", WARN_TIME));
 311 
 312         for (i = 0; i < MAX_RESETS; i++) {
 313                 load_tables();
 314                 while (wait_for_pids() == 1) {
 315                         now = time(NULL);
 316                         if ((now - curtime) >= WARN_TIME) {
 317                                 dprintf(("utmp warning timer expired\n"));
 318                                 warn_utmp();
 319                                 curtime = now;
 320                         }
 321                 }
 322         }
 323 
 324         (void) close(WTMPXfd);
 325 
 326         /*
 327          * We only get here if we had a bunch of resets - so give up
 328          */
 329         fatal("Too many resets, giving up");
 330         return (1);
 331 }
 332 
 333 /*
 334  * load_tables()        - Designed to be called repeatedly if we need to
 335  *                        restart things.  Zeros the pidcount, and loads
 336  *                        the tables by scanning utmpx
 337  */
 338 
 339 static void
 340 load_tables()
 341 {
 342         int i;
 343 
 344         dprintf(("Load tables\n"));
 345 
 346         /*
 347          * Close any open files.
 348          */
 349         for (i = 0; i < pidcnt; i++)
 350                 (void) close(fdtable[i].fd);
 351 
 352         pidcnt = 0;
 353         Pfd = -1;
 354         setup_pipe();           /* Setup the pipe to receive messages */
 355         scan_utmps();           /* Read in USER procs entries to watch */
 356 }
 357 
 358 
 359 /*
 360  *                      *** The Watcher ***
 361  *
 362  * Wait_for_pids        - wait for the termination of a process in the table.
 363  *                        Returns 1 on normal exist, 0 on failure.
 364  */
 365 
 366 static int
 367 wait_for_pids()
 368 {
 369         register struct pollfd *pfd;
 370         register int i;
 371         pid_t pid;
 372         int ret_val = 0;
 373         int timeout;
 374         static time_t last_timeout  = 0;
 375         static int bad_error  = 0;      /* Count of POLL errors */
 376 
 377         /*
 378          * First time through we initialize last_timeout to now.
 379          */
 380         if (last_timeout == 0)
 381                 last_timeout = time(NULL);
 382 
 383         /*
 384          * Recalculate timeout - checking to see if time expired.
 385          */
 386 
 387         if ((timeout = Poll_timeout - (time(NULL) - last_timeout)) <= 0) {
 388                 timeout = Poll_timeout;
 389                 last_timeout = time(NULL);
 390                 scan_utmps();
 391         }
 392 
 393         fdtable[0].events = POLLRDNORM;
 394 
 395         for (i = 0; i < (timeout / WTMPX_ufreq); i++) {
 396 
 397                 /*
 398                  * Loop here while getting EAGAIN
 399                  */
 400 
 401                 while ((ret_val = poll(fdtable, pidcnt, WTMPX_ufreq*1000)) < 0)
 402                         if (errno == EAGAIN)
 403                                 (void) sleep(2);
 404                         else
 405                                 fatal("poll");
 406                 /*
 407                  * The results of pread(2) are discarded; we only want
 408                  * to update the access time of WTMPX_FILE.
 409                  * Periodically touching WTMPX helps determine when the
 410                  * OS became unavailable when the OS boots again .
 411                  * See PSARC 2004/462 for more information.
 412                  */
 413 
 414                 (void) pread(WTMPXfd, (void *)&pid, sizeof (pid), 0);
 415 
 416                 if (ret_val)            /* file descriptor(s) need attention */
 417                         break;
 418         }
 419 
 420         /*
 421          * If ret_val == 0 the poll timed out - reset last_time and
 422          * call scan_utmps
 423          */
 424         if (ret_val == 0) {
 425                 last_timeout = time(NULL);
 426                 scan_utmps();
 427                 return (1);
 428         }
 429 
 430         /*
 431          * Check the pipe file descriptor
 432          */
 433         if (fdtable[0].revents & POLLRDNORM) {
 434                 drain_pipe();
 435                 fdtable[0].revents = 0;
 436                 ret_val--;
 437         }
 438 
 439         (void) sleep(5);        /* Give parents time to cleanup children */
 440 
 441         /*
 442          * We got here because the status of one of the pids that
 443          * we are polling on has changed, so search the table looking
 444          * for the entry.
 445          *
 446          * The table is scanned backwards so that entries can be removed
 447          * while we go since the table is compacted from high down to low
 448          */
 449         for (i = pidcnt - 1; i > 0; i--) {
 450                 /*
 451                  * Break out of the loop if we've processed all the entries.
 452                  */
 453                 if (ret_val == 0)
 454                         break;
 455 
 456                 pfd = &fdtable[i];
 457 
 458                 if (pfd->fd < 0) {
 459                         rem_pid((pid_t)0, i, DONT_CLEAN);
 460                         continue;
 461                 }
 462                 /*
 463                  * POLLHUP      - Process terminated
 464                  */
 465                 if (pfd->revents & POLLHUP) {
 466                         psinfo_t psinfo;
 467 
 468                         if (pread(pfd->fd, &psinfo, sizeof (psinfo), (off_t)0)
 469                             != sizeof (psinfo)) {
 470                                 dprintf(("! %d: terminated, status 0x%.4x\n", \
 471                                     (int)pidtable[i].pl_pid, psinfo.pr_wstat));
 472                                 pidtable[i].pl_status = psinfo.pr_wstat;
 473 
 474                         } else {
 475                                 dprintf(("! %d: terminated\n", \
 476                                     (int)pidtable[i].pl_pid));
 477                                 pidtable[i].pl_status = 0;
 478                         }
 479                         /*
 480                          * PID gets removed when terminated only
 481                          */
 482                         rem_pid((pid_t)0, i, CLEANIT);
 483                         ret_val--;
 484                         continue;
 485                 }
 486                 /*
 487                  * POLLNVAL and POLLERR
 488                  *      These error's shouldn't occurr but until their fixed
 489                  *      we perform some simple error recovery.
 490                  */
 491                 if (pfd->revents & (POLLNVAL|POLLERR)) {
 492                         dprintf(("Poll Err = %d pid = %d i = %d\n", \
 493                             pfd->revents, (int)pidtable[i].pl_pid, i));
 494 
 495                         pid = pidtable[i].pl_pid; /* Save pid for below */
 496                         /*
 497                          * If its POLLNVAL we just remove the process for
 498                          * now, it will get picked up in the next scan.
 499                          * POLLERR pids get re-added after being deleted.
 500                          */
 501                         if (pfd->revents & POLLNVAL) {
 502                                 rem_pid((pid_t)0, i, DONT_CLEAN);
 503                         } else {                        /* Else... POLLERR */
 504                                 rem_pid((pid_t)0, i, DONT_CLEAN);
 505                                 add_pid(pid);
 506                         }
 507 
 508                         if (bad_error++ > MAX_POLL_ERRS) {
 509                                 bad_error = 0;
 510                                 return (0);     /* 0 Indicates severe error */
 511                         }
 512                         ret_val--;
 513                         continue;
 514                 }
 515 
 516                 /*
 517                  * No more bits should be set in revents but check anyway
 518                  */
 519                 if (pfd->revents != 0) {
 520                         dprintf(("%d: unknown err %d\n", \
 521                             (int)pidtable[i].pl_pid, pfd->revents));
 522 
 523                         rem_pid((pid_t)0, i, DONT_CLEAN);
 524                         ret_val--;
 525 
 526                         if (bad_error++ > MAX_POLL_ERRS) {
 527                                 bad_error = 0;
 528                                 return (0);     /* 0 Indicates severe error */
 529                         }
 530                         return (1);
 531                 }
 532         }
 533         return (1);                     /* 1 Indicates Everything okay */
 534 }
 535 
 536 /*
 537  *              *** The Scanner ***
 538  *
 539  * scan_utmps()         - Scan the utmpx file.
 540  *                        For each USER_PROCESS check
 541  *                        if its alive or dead.  If alive and its not in
 542  *                        our table to be watched, put it there.  If its
 543  *                        dead, remove it from our table and clean it up.
 544  */
 545 
 546 static void
 547 scan_utmps()
 548 {
 549         struct  utmpx   *utmpx;
 550         int     i;
 551 
 552         dprintf(("Scan utmps\n"));
 553         /*
 554          * Scan utmpx.
 555          */
 556         setutxent();
 557         while ((utmpx = getutxent()) != NULL) {
 558                 if (utmpx->ut_type == USER_PROCESS) {
 559                         /*
 560                          * Is the process alive?
 561                          */
 562                         if (proc_is_alive(utmpx->ut_pid)) {
 563                                 /*
 564                                  * Yes, the process is alive, so add it if we
 565                                  * don't have it in our table.
 566                                  */
 567                                 if (find_pid(utmpx->ut_pid, &i) == 0)
 568                                         add_pid(utmpx->ut_pid);      /* No, add it */
 569                         } else {
 570                                 /*
 571                                  * No, the process is dead, so remove it if its
 572                                  * in our table, otherwise just clean it.
 573                                  */
 574                                 if (find_pid(utmpx->ut_pid, &i) == 1)
 575                                         rem_pid(utmpx->ut_pid, i, CLEANIT);
 576                                 else
 577                                         clean_utmpx_ent(utmpx);
 578                         }
 579                 }
 580         }
 581         /*
 582          * Close it to flush the buffer.
 583          */
 584         endutxent();
 585 }
 586 
 587 
 588 /*
 589  *                      *** Receiver Routines ***
 590  */
 591 
 592 /*
 593  * setup_pipe   - Set up the pipe to read pids over
 594  */
 595 
 596 static void
 597 setup_pipe()
 598 {
 599 
 600         struct statvfs statvfs_buf;
 601         /*
 602          * This code & comments swiped from init and left stock since it works
 603          */
 604 
 605         if (Pfd < 0) {
 606                 if ((statvfs(UTMPPIPE_DIR, &statvfs_buf) == 0) &&
 607                     ((statvfs_buf.f_flag & ST_RDONLY) == 0)) {
 608                         (void) unlink(UTMPPIPE);
 609                         (void) mknod(UTMPPIPE, S_IFIFO | 0600, 0);
 610                 }
 611                 Pfd = open(UTMPPIPE, O_RDWR | O_NDELAY);
 612         }
 613         if (Pfd < 0)
 614                 nonfatal(UTMPPIPE);
 615         /*
 616          * This code from init modified to be poll based instead of SIGPOLL,
 617          * signal based.
 618          */
 619 
 620         if (Pfd >= 0) {
 621                 /*
 622                  * Read pipe in message discard mode.  When read reads a
 623                  * pidrec size record, the remainder of the message will
 624                  * be discarded.  Though there shouldn't be any it will
 625                  * help resynch if someone else wrote some garbage.
 626                  */
 627                 (void) ioctl(Pfd, I_SRDOPT, RMSGD);
 628         }
 629 
 630         /*
 631          * My code.  We use slot 0 in the table to hold the fd of the pipe
 632          */
 633         add_pid(0);                     /* Proc 0 guaranteed to get slot 0 */
 634         fdtable[0].fd = Pfd;            /* Pfd could be -1, should be okay */
 635         fdtable[0].events = POLLRDNORM;
 636 }
 637 
 638 /*
 639  * drain_pipe()         - The receiver routine that reads the pipe
 640  */
 641 
 642 static void
 643 drain_pipe()
 644 {
 645         struct pidrec prec;
 646         register struct pidrec *p = &prec;
 647         int bytes_read;
 648         int i;
 649 
 650         for (;;) {
 651                 /*
 652                  * Important Note: Either read will really fail (in which case
 653                  * return is all we can do) or will get EAGAIN (Pfd was opened
 654                  * O_NDELAY), in which case we also want to return.
 655                  */
 656 
 657                 if ((bytes_read = read(Pfd, p, sizeof (struct pidrec))) !=
 658                     sizeof (struct pidrec))  {
 659                         /*
 660                          * Something went wrong reading, so read until pipe
 661                          * is empty
 662                          */
 663                         if (bytes_read > 0)
 664                                 while (read(Pfd, p, sizeof (struct pidrec)) > 0)
 665                                         ;
 666                         return;
 667                 }
 668 
 669                 dprintf(("drain_pipe: Recd command %d, pid %d\n",
 670                     p->pd_type, (int)p->pd_pid));
 671                 switch (p->pd_type) {
 672                 case ADDPID:
 673                         /*
 674                          * Check if we already have the process, adding it
 675                          * if we don't.
 676                          */
 677                         if (find_pid(p->pd_pid, &i) == 0)
 678                                 add_pid(p->pd_pid);
 679                         break;
 680 
 681                 case REMPID:
 682                         rem_pid(p->pd_pid, -1, DONT_CLEAN);
 683                         break;
 684                 default:
 685                         nonfatal("Bad message on utmppipe\n");
 686                                 break;
 687                 }
 688         }
 689 }
 690 
 691 
 692 /*
 693  *              *** Utilities for add and removing entries in the tables ***
 694  */
 695 
 696 /*
 697  * add_pid      - add a pid to the fd table and the pidtable.
 698  *                these tables are sorted tables for quick lookups.
 699  *
 700  */
 701 static void
 702 add_pid(pid_t pid)
 703 {
 704         int fd = 0;
 705         int i = 0, move_amt;
 706         int j;
 707         static int first_time = 1;
 708 
 709         /*
 710          * Check to see if the pid is already in our table, or being passed
 711          * pid zero.
 712          */
 713         if (pidcnt != 0 && (find_pid(pid, &j) == 1 || pid == 0))
 714                 return;
 715 
 716         if (pidcnt >= Max_fds) {
 717                 if (first_time == 1) {
 718                         /*
 719                          * Print this error only once
 720                          */
 721                         nonfatal("File Descriptor limit exceeded");
 722                         first_time = 0;
 723                 }
 724                 return;
 725         }
 726         /*
 727          * Open the /proc file checking if there's still a valid proc file.
 728          */
 729         if (pid != 0 && (fd = proc_to_fd(pid)) == -1) {
 730                 /*
 731                  * No so the process died before we got to watch for him
 732                  */
 733                 return;
 734         }
 735 
 736         /*
 737          * We only do this code if we're not putting in the first element
 738          * Which we know will be for proc zero which is used by setup_pipe
 739          * for its pipe fd.
 740          */
 741         if (pidcnt != 0) {
 742                 for (i = 0; i < pidcnt; i++) {
 743                         if (pid <= pidtable[i].pl_pid)
 744                                 break;
 745                 }
 746 
 747                 /*
 748                  * Handle the case where we're not sticking our entry on the
 749                  * the end, or overwriting an existing entry.
 750                  */
 751                 if (i != pidcnt && pid != pidtable[i].pl_pid) {
 752 
 753                         move_amt = pidcnt - i;
 754                         /*
 755                          * Move table down
 756                          */
 757                         if (move_amt != 0) {
 758                                 (void) memmove(&pidtable[i+1], &pidtable[i],
 759                                     move_amt * sizeof (struct pidentry));
 760                                 (void) memmove(&fdtable[i+1], &fdtable[i],
 761                                     move_amt * sizeof (pollfd_t));
 762                         }
 763                 }
 764         }
 765 
 766         /*
 767          * Fill in the events field for poll and copy the entry into the array
 768          */
 769         fdtable[i].events = 0;
 770         fdtable[i].revents = 0;
 771         fdtable[i].fd = fd;
 772 
 773         /*
 774          * Likewise, setup pid field and pointer (index) to the fdtable entry
 775          */
 776         pidtable[i].pl_pid = pid;
 777 
 778         pidcnt++;                       /* Bump the pid count */
 779         dprintf(("  add_pid: pid = %d fd = %d index = %d pidcnt = %d\n",
 780             (int)pid, fd, i, pidcnt));
 781 }
 782 
 783 
 784 /*
 785  * rem_pid      - Remove an entry from the table and check to see if its
 786  *                not in the utmpx file.
 787  *                If i != -1 don't look up the pid, use i as index
 788  *
 789  * pid          - Pid of process to clean or 0 if we don't know it
 790  *
 791  * i            - Index into table or -1 if we need to look it up
 792  *
 793  * clean_it     - Clean the entry, or just remove from table?
 794  */
 795 
 796 static void
 797 rem_pid(pid_t pid, int i, int clean_it)
 798 {
 799         int move_amt;
 800 
 801         dprintf(("  rem_pid: pid = %d i = %d", (int)pid, i));
 802 
 803         /*
 804          * Don't allow slot 0 in the table to be removed - utmppipe fd
 805          */
 806         if ((i == -1 && pid == 0) || (i == 0))  {
 807                 dprintf((" - attempted to remove proc 0\n"));
 808                 return;
 809         }
 810 
 811         if (i != -1 || find_pid(pid, &i) == 1) {    /* Found the entry */
 812                 (void) close(fdtable[i].fd);    /* We're done with the fd */
 813 
 814                 dprintf((" fd = %d\n", fdtable[i].fd));
 815 
 816                 if (clean_it == CLEANIT)
 817                         clean_entry(i);
 818 
 819                 move_amt = (pidcnt - i) - 1;
 820                 /*
 821                  * Remove entries from the tables.
 822                  */
 823                 (void) memmove(&pidtable[i], &pidtable[i+1],
 824                     move_amt * sizeof (struct pidentry));
 825 
 826                 (void) memmove(&fdtable[i], &fdtable[i+1],
 827                     move_amt * sizeof (pollfd_t));
 828 
 829                 /*
 830                  * decrement the pid count - one less pid to worry about
 831                  */
 832                 pidcnt--;
 833         }
 834         if (i == -1)
 835                 dprintf((" - entry not found \n"));
 836 }
 837 
 838 
 839 /*
 840  * find_pid     - Returns an index into the pidtable of the specifed pid,
 841  *                else -1 if not found
 842  */
 843 
 844 static int
 845 find_pid(pid_t pid, int *i)
 846 {
 847         struct pidentry pe;
 848         struct pidentry *p;
 849 
 850         pe.pl_pid = pid;
 851         p = bsearch(&pe, pidtable, pidcnt, sizeof (struct pidentry), pidcmp);
 852 
 853         if (p == NULL)
 854                 return (0);
 855         else {
 856                 *i = p - (struct pidentry *)pidtable;
 857                 return (1);
 858         }
 859 }
 860 
 861 
 862 /*
 863  * Pidcmp - Used by besearch for sorting and finding  process IDs.
 864  */
 865 
 866 static int
 867 pidcmp(struct pidentry *a, struct pidentry *b)
 868 {
 869         if (b == NULL || a == NULL)
 870                 return (0);
 871         return (a->pl_pid - b->pl_pid);
 872 }
 873 
 874 
 875 /*
 876  * proc_to_fd   - Take a process ID and return an open file descriptor to the
 877  *                /proc file for the specified process.
 878  */
 879 static int
 880 proc_to_fd(pid_t pid)
 881 {
 882         char procname[64];
 883         int fd, dfd;
 884 
 885         (void) sprintf(procname, "/proc/%d/psinfo", (int)pid);
 886 
 887         if ((fd = open(procname, O_RDONLY)) >= 0) {
 888                 /*
 889                  * dup the fd above the low order values to assure
 890                  * stdio works for other fds - paranoia.
 891                  */
 892                 if (fd < EXTRA_MARGIN) {
 893                         dfd = fcntl(fd, F_DUPFD, EXTRA_MARGIN);
 894                         if (dfd > 0) {
 895                                 (void) close(fd);
 896                                 fd = dfd;
 897                         }
 898                 }
 899                 /*
 900                  * More paranoia - set the close on exec flag
 901                  */
 902                 (void) fcntl(fd, F_SETFD, 1);
 903                 return (fd);
 904         }
 905         if (errno == ENOENT)
 906                 return (-1);
 907 
 908         if (errno == EMFILE) {
 909                 /*
 910                  * This is fatal, since libc won't be able to allocate
 911                  * any fds for the pututxline() routines
 912                  */
 913                 fatal("Out of file descriptors");
 914         }
 915         fatal(procname);                /* Only get here on error */
 916         return (-1);
 917 }
 918 
 919 
 920 /*
 921  *              *** Utmpx Cleaning Utilities ***
 922  */
 923 
 924 /*
 925  * Clean_entry  - Cleans the specified entry - where i is an index
 926  *                into the pid_table.
 927  */
 928 static void
 929 clean_entry(int i)
 930 {
 931         struct utmpx *u;
 932 
 933         if (pidcnt == 0)
 934                 return;
 935 
 936         dprintf(("    Cleaning %d\n", (int)pidtable[i].pl_pid));
 937 
 938         /*
 939          * Double check if the process is dead.
 940          */
 941         if (proc_is_alive(pidtable[i].pl_pid)) {
 942                 dprintf(("      Bad attempt to clean %d\n",
 943                     (int)pidtable[i].pl_pid));
 944                 return;
 945         }
 946 
 947         /*
 948          * Find the entry that corresponds to this pid.
 949          * Do nothing if entry not found in utmpx file.
 950          */
 951         setutxent();
 952         while ((u = getutxent()) != NULL) {
 953                 if (u->ut_pid == pidtable[i].pl_pid) {
 954                         if (u->ut_type == USER_PROCESS) {
 955                                 clean_utmpx_ent(u);
 956                         }
 957                 }
 958         }
 959         endutxent();
 960 }
 961 
 962 
 963 /*
 964  * clean_utmpx_ent      - Clean a utmpx entry
 965  */
 966 
 967 static void
 968 clean_utmpx_ent(struct utmpx *u)
 969 {
 970         dprintf(("      clean_utmpx_ent: %d\n", (int)u->ut_pid));
 971         u->ut_type = DEAD_PROCESS;
 972         (void) time(&u->ut_xtime);
 973         (void) pututxline(u);
 974         updwtmpx(WTMPX_FILE, u);
 975         /*
 976          * XXX update wtmp for ! nonuserx entries?
 977          */
 978 }
 979 
 980 /*
 981  *              *** Error Handling and Debugging Routines ***
 982  */
 983 
 984 /*
 985  * fatal - Catastrophic failure
 986  */
 987 
 988 static void
 989 fatal(char *str)
 990 {
 991         int oerrno = errno;
 992 
 993         syslog(LOG_ALERT, "%s", str);
 994         if (Debug == 1) {
 995                 if ((errno = oerrno) != 0)
 996                         perror(prog_name);
 997                 dprintf(("%s\n", str));
 998         }
 999         exit(1);
1000 }
1001 
1002 /*
1003  * nonfatal - Non-Catastrophic failure - print message and errno
1004  */
1005 
1006 static void
1007 nonfatal(char *str)
1008 {
1009         syslog(LOG_WARNING, "%s", str);
1010 
1011         if (Debug == 1) {
1012                 if (errno != 0)
1013                         perror(prog_name);
1014                 dprintf(("%c%s\n", 7, str));
1015                 print_tables();
1016                 (void) sleep(5);        /* Time to read debug messages */
1017         }
1018 }
1019 
1020 /*
1021  * print_tables - Print internal tables - for debugging
1022  */
1023 
1024 static void
1025 print_tables()
1026 {
1027         int i;
1028 
1029         if (Debug == 0)
1030                 return;
1031 
1032         dprintf(("pidtable: "));
1033         for (i = 0; i < pidcnt; i++)
1034                 dprintf(("%d: %d  ", i, (int)pidtable[i].pl_pid));
1035         dprintf(("\n"));
1036         dprintf(("fdtable:  "));
1037         for (i = 0; i < pidcnt; i++)
1038                 dprintf(("%d: %d  ", i, fdtable[i].fd));
1039         dprintf(("\n"));
1040 }
1041 
1042 /*
1043  * proc_is_alive        - Check to see if a process is alive AND its
1044  *                        not a zombie.  Returns 1 if process is alive
1045  *                        and zero if it is dead or a zombie.
1046  */
1047 
1048 static int
1049 proc_is_alive(pid_t pid)
1050 {
1051         char psinfoname[64];
1052         int fd;
1053         psinfo_t psinfo;
1054 
1055         if (kill(pid, 0) != 0)
1056                 return (0);             /* Kill failed - no process */
1057 
1058         /*
1059          * The process exists, so check if it's a zombie.
1060          */
1061         (void) sprintf(psinfoname, "/proc/%d/psinfo", (int)pid);
1062 
1063         if ((fd = open(psinfoname, O_RDONLY)) < 0 ||
1064             read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
1065                 /*
1066                  * We either couldn't open the proc, or we did but the
1067                  * read of the psinfo file failed, so pid is nonexistent.
1068                  */
1069                 psinfo.pr_nlwp = 0;
1070         }
1071         if (fd >= 0)
1072                 (void) close(fd);
1073 
1074         /* if pr_nlwp == 0, process is a zombie */
1075         return (psinfo.pr_nlwp != 0);
1076 }
1077 
1078 /*
1079  * warn_utmp -  /var/adm/utmp has been deprecated. It should no longer
1080  *              be used.  Applications that try to directly manipulate
1081  *              it may cause problems. Since the file is no longer
1082  *              shipped, if it appears on a system it's because an
1083  *              old application created it.  We'll have utmpd
1084  *              complain about it periodically.
1085  */
1086 
1087 static void
1088 warn_utmp()
1089 {
1090         struct stat s;
1091 
1092         if (lstat(UTMP_FILE, &s) == 0 &&
1093             s.st_size % sizeof (struct utmp) == 0) {
1094                 nonfatal("WARNING: /var/adm/utmp exists!\nSee "
1095                     "utmp(4) for more information");
1096         }
1097 }
1098 
1099 /*
1100  * validate_default - validate and assign defaults.
1101  */
1102 
1103 static int
1104 validate_default(char *defp, int *flag)
1105 {
1106         long lval;
1107         char *endptr;
1108 
1109         errno = 0;
1110         lval = strtol(defp, &endptr, 10);
1111 
1112         if (errno != 0 || lval > INT_MAX || lval <= 0)
1113                 return (-1);
1114 
1115         while (isspace(*endptr) != 0)
1116                 endptr++;
1117 
1118         if (*endptr != '\0')
1119                 return (-1);
1120 
1121         *flag = lval;
1122         return (0);
1123 }