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