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