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