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