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
116struct	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
130struct	pidentry {
131	pid_t	pl_pid;			/* pid to watch for */
132	int	pl_status;		/* Exit status of proc */
133};
134
135static struct pidentry *pidtable = NULL;
136
137static pollfd_t *fdtable = NULL;
138
139static int	pidcnt = 0;		/* Number of procs being watched */
140static char	*prog_name;		/* To save the invocation name away */
141static char	*UTMPPIPE_DIR =	"/var/run";
142static char	*UTMPPIPE = "/var/run/utmppipe";
143static int	Pfd = -1;		/* File descriptor of named pipe */
144static int	Poll_timeout = POLL_TIMEOUT;
145static int	WTMPXfd = -1;		/* File descriptor of WTMPX_FILE */
146static int	WTMPX_ufreq = WTMPX_UFREQ;
147static int	Debug = 0;		/* Set by command line argument */
148static 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
160static int wait_for_pids();	/* Watcher - uses poll */
161static void scan_utmps();	/* Scanner, reads utmpx file */
162static void drain_pipe();	/* Receiver - reads mesgs over UTMPPIPE */
163static void setup_pipe();	/* For setting up receiver */
164
165static void add_pid();		/* Adds a process to the table */
166static void rem_pid();		/* Removes a process from the table */
167static int find_pid();		/* Finds a process in the table */
168static int proc_to_fd();	/* Takes a pid and returns an fd for its proc */
169static void load_tables();	/* Loads up the tables the first time around */
170static int pidcmp();		/* For sorting pids */
171
172static void clean_entry();	/* Removes entry from our table and calls ... */
173static void clean_utmpx_ent();	/* Cleans a utmpx entry */
174
175static void fatal() __NORETURN;	/* Prints error message and calls exit */
176static void nonfatal();		/* Prints error message */
177static void print_tables();	/* Prints out internal tables for Debug */
178static int proc_is_alive(pid_t pid);	/* Check if a process is alive */
179static void warn_utmp(void);
180
181/* Validate defaults from file and assign */
182static 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
188int
189main(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
340static void
341load_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
367static int
368wait_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
547static void
548scan_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
597static void
598setup_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
643static void
644drain_pipe()
645{
646	struct pidrec prec;
647	register struct pidrec *p = &prec;
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 */
702static void
703add_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
797static void
798rem_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
845static int
846find_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
867static int
868pidcmp(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 */
880static int
881proc_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 */
929static void
930clean_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
968static void
969clean_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
989static void
990fatal(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
1007static void
1008nonfatal(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
1025static void
1026print_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
1049static int
1050proc_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
1088static void
1089warn_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
1104static int
1105validate_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