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 = ≺ 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 }