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