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 2004 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(); /* 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 void 182 main(argc, argv) 183 char **argv; 184 { 185 char *defp; 186 struct rlimit rlim; 187 char tstr[80]; 188 int i; 189 time_t curtime, now; 190 191 prog_name = argv[0]; /* Save invocation name */ 192 193 if (getuid() != 0) { 194 (void) fprintf(stderr, 195 "You must be root to run this program\n"); 196 fatal("You must be root to run this program"); 197 } 198 199 if (argc > 1) { 200 if ((argc == 2 && (int)strlen(argv[1]) >= 2) && 201 (argv[1][0] == '-' && argv[1][1] == 'd')) { 202 Debug = 1; 203 } else { 204 (void) fprintf(stderr, 205 "%s: Wrong number of arguments\n", prog_name); 206 (void) fprintf(stderr, 207 "Usage: %s [-debug]\n", prog_name); 208 exit(-1); 209 } 210 } 211 212 /* 213 * Read defaults file for poll timeout 214 */ 215 if (defopen(UTMP_DEFAULT) == 0) { 216 if ((defp = defread("SCAN_PERIOD=")) != NULL) { 217 Poll_timeout = atol(defp); 218 dprintf(("Poll timeout set to %d\n", Poll_timeout)); 219 } 220 221 if ((defp = defread("WTMPX_UPDATE_FREQ=")) != NULL) { 222 WTMPX_ufreq = atol(defp); 223 dprintf(("WTMPX update frequency set to %d\n", 224 WTMPX_ufreq)); 225 } 226 227 /* 228 * Paranoia - if polling on large number of FDs is expensive / 229 * buggy the number can be set lower in the field. 230 */ 231 if ((defp = defread("MAX_FDS=")) != NULL) { 232 Max_fds = atol(defp); 233 dprintf(("Max_fds set to %d\n", Max_fds)); 234 } 235 (void) defopen((char *)NULL); 236 } 237 238 if (Debug == 0) { 239 /* 240 * Daemonize ourselves 241 */ 242 if (fork()) { 243 exit(0); 244 } 245 (void) close(0); 246 (void) close(1); 247 (void) close(2); 248 /* 249 * We open these to avoid accidentally writing to a proc file 250 */ 251 (void) open("/dev/null", O_RDONLY); 252 (void) open("/dev/null", O_WRONLY); 253 (void) open("/dev/null", O_WRONLY); 254 (void) setsid(); /* release process from tty */ 255 } 256 257 openlog(prog_name, LOG_PID, LOG_DAEMON); /* For error messages */ 258 warn_utmp(); /* check to see if utmp came back by accident */ 259 260 /* 261 * Allocate the pidtable and fdtable. An earlier version did 262 * this as we go, but this is simpler. 263 */ 264 if ((pidtable = malloc(Max_fds * sizeof (struct pidentry))) == NULL) 265 fatal("Malloc failed"); 266 if ((fdtable = malloc(Max_fds * sizeof (pollfd_t))) == NULL) 267 fatal("Malloc failed"); 268 269 /* 270 * Up the limit on FDs 271 */ 272 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 273 rlim.rlim_cur = Max_fds + EXTRA_MARGIN + 1; 274 rlim.rlim_max = Max_fds + EXTRA_MARGIN + 1; 275 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { 276 fatal("Out of File Descriptors"); 277 } 278 } else 279 fatal("getrlimit returned failure"); 280 281 if ((WTMPXfd = open(WTMPX_FILE, O_RDONLY)) < 0) 282 nonfatal("WARNING: unable to open " WTMPX_FILE "for update."); 283 284 /* 285 * Loop here scanning the utmpx file and waiting for processes 286 * to terminate. Most of the activity is directed out of wait_for_pids. 287 * If wait_for_pids fails we reload the table and try again. 288 */ 289 290 curtime = time(NULL); 291 dprintf(("utmp warning timer set to %d seconds\n", WARN_TIME)); 292 293 for (i = 0; i < MAX_RESETS; i++) { 294 load_tables(); 295 while (wait_for_pids() == 1) { 296 now = time(NULL); 297 if ((now - curtime) >= WARN_TIME) { 298 dprintf(("utmp warning timer expired\n")); 299 warn_utmp(); 300 curtime = now; 301 } 302 } 303 } 304 305 (void) close(WTMPXfd); 306 307 /* 308 * We only get here if we had a bunch of resets - so give up 309 */ 310 fatal("Too many resets, giving up"); 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, \ 474 (int)pidtable[i].pl_pid, i)); 475 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, 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, 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 } 1085