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 }