xref: /illumos-gate/usr/src/cmd/ttymon/tmhandler.c (revision 3bb2c156)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27*3bb2c156SToomas Soome /*	  All Rights Reserved	*/
282756274fSJohn Levon /*
292756274fSJohn Levon  * Copyright (c) 2018, Joyent, Inc.
302756274fSJohn Levon  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <poll.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <termio.h>
407c478bd9Sstevel@tonic-gate #include <signal.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
447c478bd9Sstevel@tonic-gate #include <sys/wait.h>
457c478bd9Sstevel@tonic-gate #include "ttymon.h"
467c478bd9Sstevel@tonic-gate #include "tmstruct.h"
477c478bd9Sstevel@tonic-gate #include "tmextern.h"
487c478bd9Sstevel@tonic-gate #include "sac.h"
497c478bd9Sstevel@tonic-gate 
50*3bb2c156SToomas Soome static	struct	pmtab	*find_pid(pid_t);
51*3bb2c156SToomas Soome static	void	kill_subprocesses(void);
527c478bd9Sstevel@tonic-gate 
53*3bb2c156SToomas Soome static	struct	pmtab	*find_fd(int);
54*3bb2c156SToomas Soome static	void	pcsync_close(int *, int *, int, int);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  *	fork_tmchild	- fork child on the device
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate static	void
fork_tmchild(struct pmtab * pmptr)60*3bb2c156SToomas Soome fork_tmchild(struct pmtab *pmptr)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	pid_t	pid;
637c478bd9Sstevel@tonic-gate 	sigset_t	cset;
647c478bd9Sstevel@tonic-gate 	sigset_t	tset;
657c478bd9Sstevel@tonic-gate 	int	pcpipe0[2], pcpipe1[2];
667c478bd9Sstevel@tonic-gate 	int	p0;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #ifdef	DEBUG
697c478bd9Sstevel@tonic-gate 	debug("in fork_tmchild");
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate 	pmptr->p_inservice = FALSE;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	/*
74*3bb2c156SToomas Soome 	 * initialize pipe.
757c478bd9Sstevel@tonic-gate 	 * Child has pcpipe[0] pipe fd for reading and writing
767c478bd9Sstevel@tonic-gate 	 * and closes pcpipe[1]. Parent has pcpipe[1] pipe fd for
777c478bd9Sstevel@tonic-gate 	 * reading and writing and closes pcpipe[0].
787c478bd9Sstevel@tonic-gate 	 *
797c478bd9Sstevel@tonic-gate 	 * This way if the child process exits the parent's block
807c478bd9Sstevel@tonic-gate 	 * read on pipe will return immediately as the other end of
817c478bd9Sstevel@tonic-gate 	 * the pipe has closed. Similarly if the parent process exits
827c478bd9Sstevel@tonic-gate 	 * child's blocking read on the pipe will return immediately.
837c478bd9Sstevel@tonic-gate 	 */
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	if (((p0 = pipe(pcpipe0)) == -1) || (pipe(pcpipe1) == -1))  {
867c478bd9Sstevel@tonic-gate 		if (p0 == 0) {
87*3bb2c156SToomas Soome 			(void) close(pcpipe0[0]);
88*3bb2c156SToomas Soome 			(void) close(pcpipe0[1]);
897c478bd9Sstevel@tonic-gate 		}
907c478bd9Sstevel@tonic-gate 		log("pipe() failed: %s", strerror(errno));
917c478bd9Sstevel@tonic-gate 		pmptr->p_status = VALID;
92*3bb2c156SToomas Soome 		pmptr->p_childpid = 0;
937c478bd9Sstevel@tonic-gate 		Retry = TRUE;
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/* protect following region from SIGCLD */
97*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, NULL, &cset);
987c478bd9Sstevel@tonic-gate 	tset = cset;
99*3bb2c156SToomas Soome 	(void) sigaddset(&tset, SIGCLD);
100*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, &tset, NULL);
101*3bb2c156SToomas Soome 	if ((pid = fork()) == 0) {
1027c478bd9Sstevel@tonic-gate 		/*
1037c478bd9Sstevel@tonic-gate 		 * Close all file descriptors except pmptr->p_fd
1047c478bd9Sstevel@tonic-gate 		 * Wait for the parent process to close its fd
1057c478bd9Sstevel@tonic-gate 		 */
1067c478bd9Sstevel@tonic-gate 		pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
107*3bb2c156SToomas Soome 		/* The CHILD */
108*3bb2c156SToomas Soome 		tmchild(pmptr);
1097c478bd9Sstevel@tonic-gate 		/* tmchild should never return */
1107c478bd9Sstevel@tonic-gate 		fatal("tmchild for <%s> returns unexpected", pmptr->p_device);
111*3bb2c156SToomas Soome 	} else if (pid < 0) {
1127c478bd9Sstevel@tonic-gate 		log("fork failed: %s", strerror(errno));
1137c478bd9Sstevel@tonic-gate 		pmptr->p_status = VALID;
114*3bb2c156SToomas Soome 		pmptr->p_childpid = 0;
1157c478bd9Sstevel@tonic-gate 		Retry = TRUE;
116*3bb2c156SToomas Soome 	} else {
1177c478bd9Sstevel@tonic-gate 		/*
1187c478bd9Sstevel@tonic-gate 		 * The PARENT - store pid of child and close the device
1197c478bd9Sstevel@tonic-gate 		 */
120*3bb2c156SToomas Soome 		pmptr->p_childpid = pid;
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 	if (pmptr->p_fd > 0) {
123*3bb2c156SToomas Soome 		(void) close(pmptr->p_fd);
124*3bb2c156SToomas Soome 		pmptr->p_fd = 0;
1257c478bd9Sstevel@tonic-gate 	}
126*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, &cset, NULL);
1277c478bd9Sstevel@tonic-gate 	/*
1287c478bd9Sstevel@tonic-gate 	 * Wait for child to close file descriptors
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * got_carrier - carrier is detected on the stream
1357c478bd9Sstevel@tonic-gate  *	       - depends on the flags, different action is taken
1367c478bd9Sstevel@tonic-gate  *	       - R_FLAG - wait for data
1377c478bd9Sstevel@tonic-gate  *	       - C_FLAG - if port is not disabled, fork tmchild
138*3bb2c156SToomas Soome  *	       - A_FLAG - wait for data
1397c478bd9Sstevel@tonic-gate  *	       - otherwise - write out prompt, then wait for data
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate void
got_carrier(struct pmtab * pmptr)142*3bb2c156SToomas Soome got_carrier(struct pmtab *pmptr)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	flush_input(pmptr->p_fd);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	if (pmptr->p_ttyflags & R_FLAG) {
1477c478bd9Sstevel@tonic-gate #ifdef	DEBUG
148*3bb2c156SToomas Soome 		debug("R_FLAG");
1497c478bd9Sstevel@tonic-gate #endif
1507c478bd9Sstevel@tonic-gate 		return;
151*3bb2c156SToomas Soome 	} else if ((pmptr->p_ttyflags & (C_FLAG|B_FLAG)) &&
152*3bb2c156SToomas Soome 	    (State != PM_DISABLED) &&
153*3bb2c156SToomas Soome 	    (!(pmptr->p_flags & X_FLAG))) {
1547c478bd9Sstevel@tonic-gate 		fork_tmchild(pmptr);
155*3bb2c156SToomas Soome 	} else if (pmptr->p_ttyflags & A_FLAG) {
1567c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1577c478bd9Sstevel@tonic-gate 	debug("A_FLAG");
1587c478bd9Sstevel@tonic-gate #endif
1597c478bd9Sstevel@tonic-gate 		return;
160*3bb2c156SToomas Soome 	} else if (pmptr->p_timeout) {
1617c478bd9Sstevel@tonic-gate 		fork_tmchild(pmptr);
162*3bb2c156SToomas Soome 	} else if (!(pmptr->p_ttyflags & X_FLAG)) {
163*3bb2c156SToomas Soome 		write_prompt(pmptr->p_fd, pmptr, TRUE, TRUE);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * got_data - data is detected on the stream, fork tmchild
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate static void
got_data(struct pmtab * pmptr)171*3bb2c156SToomas Soome got_data(struct pmtab *pmptr)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	struct	sigaction sigact;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (tm_checklock(pmptr->p_fd) != 0) {
1767c478bd9Sstevel@tonic-gate 		pmptr->p_status = LOCKED;
177*3bb2c156SToomas Soome 		(void) close(pmptr->p_fd);
1787c478bd9Sstevel@tonic-gate 		pmptr->p_fd = 0;
1797c478bd9Sstevel@tonic-gate 		Nlocked++;
1807c478bd9Sstevel@tonic-gate 		if (Nlocked == 1) {
1817c478bd9Sstevel@tonic-gate 			sigact.sa_flags = 0;
1827c478bd9Sstevel@tonic-gate 			sigact.sa_handler = sigalarm;
183*3bb2c156SToomas Soome 			(void) sigemptyset(&sigact.sa_mask);
184*3bb2c156SToomas Soome 			(void) sigaction(SIGALRM, &sigact, NULL);
185*3bb2c156SToomas Soome 			(void) alarm(ALARMTIME);
1867c478bd9Sstevel@tonic-gate 		}
187*3bb2c156SToomas Soome 	} else {
1887c478bd9Sstevel@tonic-gate 		fork_tmchild(pmptr);
189*3bb2c156SToomas Soome 	}
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate  * got_hup - stream hangup is detected, close the device
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate static void
got_hup(struct pmtab * pmptr)195*3bb2c156SToomas Soome got_hup(struct pmtab *pmptr)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1987c478bd9Sstevel@tonic-gate 	debug("in got hup");
1997c478bd9Sstevel@tonic-gate #endif
200*3bb2c156SToomas Soome 	(void) close(pmptr->p_fd);
2017c478bd9Sstevel@tonic-gate 	pmptr->p_fd = 0;
2027c478bd9Sstevel@tonic-gate 	pmptr->p_inservice = 0;
2037c478bd9Sstevel@tonic-gate 	Retry = TRUE;
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  *	do_poll	- poll device
2097c478bd9Sstevel@tonic-gate  *		- if POLLHUP received, close the device
2107c478bd9Sstevel@tonic-gate  *		- if POLLIN received, fork tmchild.
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate void
do_poll(struct pollfd * fdp,int nfds)213*3bb2c156SToomas Soome do_poll(struct  pollfd *fdp, int nfds)
2147c478bd9Sstevel@tonic-gate {
215*3bb2c156SToomas Soome 	int	i, n;
2167c478bd9Sstevel@tonic-gate 	struct	pmtab	*pmptr;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	n = poll(fdp, (unsigned long)nfds, -1);	/* blocked poll */
2197c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2207c478bd9Sstevel@tonic-gate 	debug("poll return");
2217c478bd9Sstevel@tonic-gate #endif
2227c478bd9Sstevel@tonic-gate 	if (n < 0) {
2237c478bd9Sstevel@tonic-gate 		if (errno == EINTR)	/* interrupt by signal */
2247c478bd9Sstevel@tonic-gate 			return;
2257c478bd9Sstevel@tonic-gate 		fatal("do_poll: poll failed: %s", strerror(errno));
2267c478bd9Sstevel@tonic-gate 	}
227*3bb2c156SToomas Soome 	for (i = 0; (i < nfds) && (n != 0); i++, fdp++) {
2287c478bd9Sstevel@tonic-gate 		if (fdp->revents != 0) {
2297c478bd9Sstevel@tonic-gate 			n--;
2307c478bd9Sstevel@tonic-gate 			if ((pmptr = find_fd(fdp->fd)) == NULL) {
2317c478bd9Sstevel@tonic-gate 				log("do_poll: cannot find fd %d in pmtab",
2327c478bd9Sstevel@tonic-gate 				    fdp->fd);
2337c478bd9Sstevel@tonic-gate 				continue;
234*3bb2c156SToomas Soome 			} else if (fdp->revents & POLLHUP) {
2357c478bd9Sstevel@tonic-gate 				got_hup(pmptr);
236*3bb2c156SToomas Soome 			} else if (fdp->revents & POLLIN) {
2377c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2387c478bd9Sstevel@tonic-gate 				debug("got POLLIN");
2397c478bd9Sstevel@tonic-gate #endif
2407c478bd9Sstevel@tonic-gate 				got_data(pmptr);
2417c478bd9Sstevel@tonic-gate 			} else if (fdp->revents & POLLERR) {
2427c478bd9Sstevel@tonic-gate 				fatal("ttymon[%d]: do_poll: POLLERR on fd %d",
2437c478bd9Sstevel@tonic-gate 				    getpid(), fdp->fd);
2447c478bd9Sstevel@tonic-gate 			}
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate  *	sigchild	- handler for SIGCLD
2517c478bd9Sstevel@tonic-gate  *			- find the pid of dead child
2527c478bd9Sstevel@tonic-gate  *			- clean utmp if U_FLAG is set
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate void
sigchild(int n __unused)255*3bb2c156SToomas Soome sigchild(int n __unused)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	struct	pmtab	*pmptr;
2587c478bd9Sstevel@tonic-gate 	siginfo_t	info;
259*3bb2c156SToomas Soome 	int	status;
260*3bb2c156SToomas Soome 	pid_t	pid;
2617c478bd9Sstevel@tonic-gate 	int	rcode;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2647c478bd9Sstevel@tonic-gate 	debug("in sigchild");
2657c478bd9Sstevel@tonic-gate #endif
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* find all processes that died */
2687c478bd9Sstevel@tonic-gate 	for (;;) {
2697c478bd9Sstevel@tonic-gate 		rcode = waitid(P_ALL, 0, &info, WNOHANG|WEXITED);
2707c478bd9Sstevel@tonic-gate 		if (rcode == -1 && errno == EINTR)
2717c478bd9Sstevel@tonic-gate 			continue;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		/* If no more children have exited, just return */
2747c478bd9Sstevel@tonic-gate 		if (rcode == -1 || (pid = info.si_pid) == 0)
2757c478bd9Sstevel@tonic-gate 			break;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		/* construct status as returned from waitid() */
2787c478bd9Sstevel@tonic-gate 		status = info.si_status & 0377;
2797c478bd9Sstevel@tonic-gate 		switch (info.si_code) {
2807c478bd9Sstevel@tonic-gate 		case CLD_EXITED:
2817c478bd9Sstevel@tonic-gate 			status <<= 8;
2827c478bd9Sstevel@tonic-gate 			break;
2837c478bd9Sstevel@tonic-gate 		case CLD_DUMPED:
2847c478bd9Sstevel@tonic-gate 			status |= WCOREFLG;
2857c478bd9Sstevel@tonic-gate 			break;
2867c478bd9Sstevel@tonic-gate 		case CLD_KILLED:
2877c478bd9Sstevel@tonic-gate 			break;
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		if ((pmptr = find_pid(pid)) == NULL) {
2917c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2927c478bd9Sstevel@tonic-gate 			log("cannot find dead child (%ld) in pmtab", pid);
2937c478bd9Sstevel@tonic-gate #endif
2947c478bd9Sstevel@tonic-gate 			/*
2957c478bd9Sstevel@tonic-gate 			 * This may happen if the entry is deleted from pmtab
2967c478bd9Sstevel@tonic-gate 			 * before the service exits.
2977c478bd9Sstevel@tonic-gate 			 * We try to cleanup utmp entry
2987c478bd9Sstevel@tonic-gate 			 */
2997c478bd9Sstevel@tonic-gate 			cleanut(pid, status);
3007c478bd9Sstevel@tonic-gate 		} else {
3017c478bd9Sstevel@tonic-gate 			if (pmptr->p_flags & U_FLAG)
3027c478bd9Sstevel@tonic-gate 				cleanut(pid, status);
3037c478bd9Sstevel@tonic-gate 			pmptr->p_status = VALID;
3047c478bd9Sstevel@tonic-gate 			pmptr->p_fd = 0;
305*3bb2c156SToomas Soome 			pmptr->p_childpid = 0;
3067c478bd9Sstevel@tonic-gate 			pmptr->p_inservice = 0;
3077c478bd9Sstevel@tonic-gate 			Retry = TRUE;
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  *	sigterm	- handler for SIGTERM
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate void
sigterm(int _s __unused)316*3bb2c156SToomas Soome sigterm(int _s __unused)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	fatal("caught SIGTERM");
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  *	state_change	- this is called when ttymon changes
3237c478bd9Sstevel@tonic-gate  *			  its internal state between enabled and disabled
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate void
state_change(void)326*3bb2c156SToomas Soome state_change(void)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	struct pmtab *pmptr;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate #ifdef	DEBUG
3317c478bd9Sstevel@tonic-gate 	debug("in state_change");
3327c478bd9Sstevel@tonic-gate #endif
3337c478bd9Sstevel@tonic-gate 
334*3bb2c156SToomas Soome 	/*
335*3bb2c156SToomas Soome 	 * closing PCpipe will cause attached non-service children
3367c478bd9Sstevel@tonic-gate 	 * to get SIGPOLL and exit
3377c478bd9Sstevel@tonic-gate 	 */
338*3bb2c156SToomas Soome 	(void) close(PCpipe[0]);
339*3bb2c156SToomas Soome 	(void) close(PCpipe[1]);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* reopen PCpipe */
3427c478bd9Sstevel@tonic-gate 	setup_PCpipe();
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/*
3457c478bd9Sstevel@tonic-gate 	 * also close all open ports so ttymon can start over
3467c478bd9Sstevel@tonic-gate 	 * with new internal state
3477c478bd9Sstevel@tonic-gate 	 */
3487c478bd9Sstevel@tonic-gate 	for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
349*3bb2c156SToomas Soome 		if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) {
350*3bb2c156SToomas Soome 			(void) close(pmptr->p_fd);
3517c478bd9Sstevel@tonic-gate 			pmptr->p_fd = 0;
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	Retry = TRUE;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate  *	re_read	- reread pmtab
3607c478bd9Sstevel@tonic-gate  *		- kill tmchild if entry changed
3617c478bd9Sstevel@tonic-gate  */
3627c478bd9Sstevel@tonic-gate void
re_read(void)363*3bb2c156SToomas Soome re_read(void)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	sigset_t	cset;
3667c478bd9Sstevel@tonic-gate 	sigset_t	tset;
3677c478bd9Sstevel@tonic-gate 
368*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, NULL, &cset);
3697c478bd9Sstevel@tonic-gate 	tset = cset;
370*3bb2c156SToomas Soome 	(void) sigaddset(&tset, SIGCLD);
371*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, &tset, NULL);
3727c478bd9Sstevel@tonic-gate 	if (Nlocked > 0) {
373*3bb2c156SToomas Soome 		(void) alarm(0);
3747c478bd9Sstevel@tonic-gate 		Nlocked = 0;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 	read_pmtab();
377*3bb2c156SToomas Soome 	kill_subprocesses();
378*3bb2c156SToomas Soome 	(void) sigprocmask(SIG_SETMASK, &cset, NULL);
3797c478bd9Sstevel@tonic-gate 	purge();
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (Nentries > Npollfd) {
3827c478bd9Sstevel@tonic-gate #ifdef	DEBUG
3837c478bd9Sstevel@tonic-gate 		debug("Nentries > Npollfd, reallocating pollfds");
3847c478bd9Sstevel@tonic-gate #endif
3857c478bd9Sstevel@tonic-gate 		/* need to malloc more pollfd structure */
386*3bb2c156SToomas Soome 		free(Pollp);
3877c478bd9Sstevel@tonic-gate 		Npollfd = Nentries + 10;
3887c478bd9Sstevel@tonic-gate 		if (Npollfd > Maxfds)
3897c478bd9Sstevel@tonic-gate 			Npollfd = Maxfds;
390*3bb2c156SToomas Soome 		Pollp = malloc((unsigned)(Npollfd * sizeof (struct pollfd)));
391*3bb2c156SToomas Soome 		if (Pollp == NULL)
3927c478bd9Sstevel@tonic-gate 			fatal("malloc for Pollp failed");
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	Retry = TRUE;
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  *	find_pid(pid)	- find the corresponding pmtab entry for the pid
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static	struct pmtab *
find_pid(pid_t pid)401*3bb2c156SToomas Soome find_pid(pid_t pid)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	struct pmtab *pmptr;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
406*3bb2c156SToomas Soome 		if (pmptr->p_childpid == pid) {
407*3bb2c156SToomas Soome 			return (pmptr);
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 	}
410*3bb2c156SToomas Soome 	return (NULL);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate  *	find_fd(fd)	- find the corresponding pmtab entry for the fd
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate static struct pmtab *
find_fd(int fd)417*3bb2c156SToomas Soome find_fd(int fd)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	struct pmtab *pmptr;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
4227c478bd9Sstevel@tonic-gate 		if (pmptr->p_fd == fd) {
423*3bb2c156SToomas Soome 			return (pmptr);
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 	}
426*3bb2c156SToomas Soome 	return (NULL);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
430*3bb2c156SToomas Soome  *	kill_subprocesses() - if the pmtab entry has been changed,
4317c478bd9Sstevel@tonic-gate  *			  kill tmchild if it is not in service.
4327c478bd9Sstevel@tonic-gate  *			- close the device if there is no tmchild
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate static	void
kill_subprocesses(void)435*3bb2c156SToomas Soome kill_subprocesses(void)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	struct pmtab *pmptr;
438*3bb2c156SToomas Soome 
4397c478bd9Sstevel@tonic-gate 	for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
4407c478bd9Sstevel@tonic-gate 		if (pmptr->p_status == VALID)
4417c478bd9Sstevel@tonic-gate 			continue;
442*3bb2c156SToomas Soome 		if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) {
443*3bb2c156SToomas Soome 			(void) close(pmptr->p_fd);
4447c478bd9Sstevel@tonic-gate 			pmptr->p_fd = 0;
445*3bb2c156SToomas Soome 		} else if ((pmptr->p_fd == 0) && (pmptr->p_childpid > 0) &&
446*3bb2c156SToomas Soome 		    (pmptr->p_inservice == FALSE)) {
447*3bb2c156SToomas Soome 			(void) kill(pmptr->p_childpid, SIGTERM);
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate static	void
mark_service(pid_t pid)453*3bb2c156SToomas Soome mark_service(pid_t pid)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	struct	pmtab	*pmptr;
4567c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4577c478bd9Sstevel@tonic-gate 	debug("in mark_service");
4587c478bd9Sstevel@tonic-gate #endif
4597c478bd9Sstevel@tonic-gate 	if ((pmptr = find_pid(pid)) == NULL) {
4607c478bd9Sstevel@tonic-gate 		log("mark_service: cannot find child (%ld) in pmtab", pid);
4617c478bd9Sstevel@tonic-gate 		return;
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 	pmptr->p_inservice = TRUE;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * read_pid(fd)	- read pid info from PCpipe
4687c478bd9Sstevel@tonic-gate  */
4697c478bd9Sstevel@tonic-gate static	void
read_pid(int fd)470*3bb2c156SToomas Soome read_pid(int fd)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	int	ret;
4737c478bd9Sstevel@tonic-gate 	pid_t	pid;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	for (;;) {
476*3bb2c156SToomas Soome 		if ((ret = read(fd, &pid, sizeof (pid))) < 0) {
4777c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
4787c478bd9Sstevel@tonic-gate 				continue;
479*3bb2c156SToomas Soome 			if (errno == EAGAIN)
4807c478bd9Sstevel@tonic-gate 				return;
4817c478bd9Sstevel@tonic-gate 			fatal("read PCpipe failed: %s", strerror(errno));
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		if (ret == 0)
4847c478bd9Sstevel@tonic-gate 			return;
485*3bb2c156SToomas Soome 		if (ret != sizeof (pid))
4867c478bd9Sstevel@tonic-gate 			fatal("read return size incorrect, ret = %d", ret);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		mark_service(pid);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate  * sipoll_catch()	- signal handle of SIGPOLL for ttymon
4947c478bd9Sstevel@tonic-gate  *			- it will check both PCpipe and pmpipe
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate void
sigpoll_catch(int s __unused)497*3bb2c156SToomas Soome sigpoll_catch(int s __unused)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	int	ret;
5007c478bd9Sstevel@tonic-gate 	struct	pollfd	pfd[2];
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate #ifdef	DEBUG
5037c478bd9Sstevel@tonic-gate 	debug("in sigpoll_catch");
5047c478bd9Sstevel@tonic-gate #endif
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	pfd[0].fd = PCpipe[0];
5077c478bd9Sstevel@tonic-gate 	pfd[1].fd = Pfd;
5087c478bd9Sstevel@tonic-gate 	pfd[0].events = POLLIN;
5097c478bd9Sstevel@tonic-gate 	pfd[1].events = POLLIN;
5107c478bd9Sstevel@tonic-gate 	if ((ret = poll(pfd, 2, 0)) < 0)
5117c478bd9Sstevel@tonic-gate 		fatal("sigpoll_catch: poll failed: %s", strerror(errno));
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (ret > 0) {
514*3bb2c156SToomas Soome 		if (pfd[0].revents & POLLIN)
5157c478bd9Sstevel@tonic-gate 			read_pid(pfd[0].fd);
5167c478bd9Sstevel@tonic-gate 		if (pfd[1].revents & POLLIN)
5177c478bd9Sstevel@tonic-gate 			sacpoll();
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate void
sigalarm(int signo __unused)522*3bb2c156SToomas Soome sigalarm(int signo __unused)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	struct pmtab *pmptr;
5257c478bd9Sstevel@tonic-gate 	struct sigaction sigact;
5267c478bd9Sstevel@tonic-gate 	int	fd;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate #ifdef	DEBUG
5297c478bd9Sstevel@tonic-gate 	debug("in sigalarm, Nlocked = %d", Nlocked);
5307c478bd9Sstevel@tonic-gate #endif
5317c478bd9Sstevel@tonic-gate 	for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
5327c478bd9Sstevel@tonic-gate 		if ((pmptr->p_status == LOCKED) && (pmptr->p_fd == 0)) {
533*3bb2c156SToomas Soome 			fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
534*3bb2c156SToomas Soome 			if (fd == -1) {
5357c478bd9Sstevel@tonic-gate 				log("open (%s) failed: %s", pmptr->p_device,
5367c478bd9Sstevel@tonic-gate 				    strerror(errno));
5377c478bd9Sstevel@tonic-gate 				pmptr->p_status = VALID;
5387c478bd9Sstevel@tonic-gate 				Nlocked--;
5397c478bd9Sstevel@tonic-gate 				Retry = TRUE;
540*3bb2c156SToomas Soome 			} else {
5417c478bd9Sstevel@tonic-gate 				if (tm_checklock(fd) == 0) {
5427c478bd9Sstevel@tonic-gate 					Nlocked--;
5437c478bd9Sstevel@tonic-gate 					pmptr->p_fd = fd;
5447c478bd9Sstevel@tonic-gate 					Retry = TRUE;
545*3bb2c156SToomas Soome 				} else {
546*3bb2c156SToomas Soome 					(void) close(fd);
5477c478bd9Sstevel@tonic-gate 				}
5487c478bd9Sstevel@tonic-gate 			}
549*3bb2c156SToomas Soome 		} else if ((pmptr->p_status == SESSION) && (pmptr->p_fd == 0)) {
550*3bb2c156SToomas Soome 			fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
551*3bb2c156SToomas Soome 			if (fd == -1) {
5527c478bd9Sstevel@tonic-gate 				log("open (%s) failed: %s", pmptr->p_device,
5537c478bd9Sstevel@tonic-gate 				    strerror(errno));
5547c478bd9Sstevel@tonic-gate 				pmptr->p_status = VALID;
5557c478bd9Sstevel@tonic-gate 				Nlocked--;
5567c478bd9Sstevel@tonic-gate 				Retry = TRUE;
557*3bb2c156SToomas Soome 			} else {
5587c478bd9Sstevel@tonic-gate 				if (check_session(fd) == 0) {
5597c478bd9Sstevel@tonic-gate 					Nlocked--;
5607c478bd9Sstevel@tonic-gate 					pmptr->p_fd = fd;
5617c478bd9Sstevel@tonic-gate 					Retry = TRUE;
562*3bb2c156SToomas Soome 				} else {
563*3bb2c156SToomas Soome 					(void) close(fd);
5647c478bd9Sstevel@tonic-gate 				}
5657c478bd9Sstevel@tonic-gate 			}
566*3bb2c156SToomas Soome 		} else if ((pmptr->p_status == UNACCESS) &&
567*3bb2c156SToomas Soome 		    (pmptr->p_fd == 0)) {
568*3bb2c156SToomas Soome 			fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
569*3bb2c156SToomas Soome 			if (fd == -1) {
5707c478bd9Sstevel@tonic-gate 				log("open (%s) failed: %s", pmptr->p_device,
5717c478bd9Sstevel@tonic-gate 				    strerror(errno));
5727c478bd9Sstevel@tonic-gate 				pmptr->p_status = VALID;
5737c478bd9Sstevel@tonic-gate 				Nlocked--;
5747c478bd9Sstevel@tonic-gate 				Retry = TRUE;
575*3bb2c156SToomas Soome 			} else {
5767c478bd9Sstevel@tonic-gate 				Nlocked--;
5777c478bd9Sstevel@tonic-gate 				pmptr->p_fd = fd;
5787c478bd9Sstevel@tonic-gate 				Retry = TRUE;
5797c478bd9Sstevel@tonic-gate 			}
5807c478bd9Sstevel@tonic-gate 		}
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 	if (Nlocked > 0) {
5837c478bd9Sstevel@tonic-gate 		sigact.sa_flags = 0;
5847c478bd9Sstevel@tonic-gate 		sigact.sa_handler = sigalarm;
585*3bb2c156SToomas Soome 		(void) sigemptyset(&sigact.sa_mask);
586*3bb2c156SToomas Soome 		(void) sigaction(SIGALRM, &sigact, NULL);
587*3bb2c156SToomas Soome 		(void) alarm(ALARMTIME);
588*3bb2c156SToomas Soome 	} else {
5897c478bd9Sstevel@tonic-gate 		sigact.sa_flags = 0;
5907c478bd9Sstevel@tonic-gate 		sigact.sa_handler = SIG_IGN;
591*3bb2c156SToomas Soome 		(void) sigemptyset(&sigact.sa_mask);
592*3bb2c156SToomas Soome 		(void) sigaction(SIGALRM, &sigact, NULL);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate  * pcsync_close -  For the child process close all open fd's except
5987c478bd9Sstevel@tonic-gate  * the one that is passed to the routine. Coordinate the reads and
5997c478bd9Sstevel@tonic-gate  * writes to the pipes by the parent and child process to ensure
6007c478bd9Sstevel@tonic-gate  * the parent and child processes have closed all the file descriptors
6017c478bd9Sstevel@tonic-gate  * that are not needed any more.
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate static void
pcsync_close(int * p0,int * p1,int pid,int fd)6042756274fSJohn Levon pcsync_close(int *p0, int *p1, int pid, int fd)
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate 	char	ch;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if (pid == 0) {				/* Child */
6097c478bd9Sstevel@tonic-gate 		struct  pmtab   *tp;
6107c478bd9Sstevel@tonic-gate 		for (tp = PMtab; tp; tp = tp->p_next)
6117c478bd9Sstevel@tonic-gate 			if ((tp->p_fd > 0) && (tp->p_fd != fd))
612*3bb2c156SToomas Soome 				(void) close(tp->p_fd);
613*3bb2c156SToomas Soome 		(void) close(p0[1]);
614*3bb2c156SToomas Soome 		(void) close(p1[0]);
6157c478bd9Sstevel@tonic-gate 		if (read(p0[0], &ch, 1) == 1)
616*3bb2c156SToomas Soome 			(void) write(p1[1], "a", 1);
617*3bb2c156SToomas Soome 		(void) close(p0[0]);
618*3bb2c156SToomas Soome 		(void) close(p1[1]);
6197c478bd9Sstevel@tonic-gate 	} else {				/* Parent */
620*3bb2c156SToomas Soome 		(void) close(p0[0]);
621*3bb2c156SToomas Soome 		(void) close(p1[1]);
6227c478bd9Sstevel@tonic-gate 		if (write(p0[1], "a", 1) == 1)
623*3bb2c156SToomas Soome 			(void) read(p1[0], &ch, 1);
624*3bb2c156SToomas Soome 		(void) close(p0[1]);
625*3bb2c156SToomas Soome 		(void) close(p1[0]);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate }
628