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