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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of such source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * utmpd - utmp daemon 39 * 40 * This program receives requests from pututxline(3) 41 * via a named pipe to watch the process to make sure it cleans up 42 * its utmpx entry on termination. 43 * The program keeps a list of procs 44 * and uses poll() on their /proc files to detect termination. 45 * Also the program periodically scans the /etc/utmpx file for 46 * processes that aren't in the table so they can be watched. 47 * 48 * If utmpd doesn't hear back over the pipe from pututline(3) that 49 * the process has removed its entry it cleans the entry when the 50 * the process terminates. 51 * The AT&T Copyright above is there since we borrowed the pipe 52 * mechanism from init(1m). 53 */ 54 55 56 #include <sys/types.h> 57 #include <signal.h> 58 #include <stdio.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 = "/etc"; 138 static char *UTMPPIPE = "/etc/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 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 = ≺ 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 ! nonuser 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 } 1083