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