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