xref: /onnv-gate/usr/src/cmd/ttymon/ttymon.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <fcntl.h>
36*0Sstevel@tonic-gate #include <errno.h>
37*0Sstevel@tonic-gate #include <poll.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #include <signal.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/stat.h>
42*0Sstevel@tonic-gate #include <sys/stropts.h>
43*0Sstevel@tonic-gate #include <sys/resource.h>
44*0Sstevel@tonic-gate #include <sys/termios.h>
45*0Sstevel@tonic-gate #include <pwd.h>
46*0Sstevel@tonic-gate #include <grp.h>
47*0Sstevel@tonic-gate #include <unistd.h>
48*0Sstevel@tonic-gate #include <ulimit.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #include "sac.h"
51*0Sstevel@tonic-gate #include "ttymon.h"
52*0Sstevel@tonic-gate #include "tmstruct.h"
53*0Sstevel@tonic-gate #include "tmextern.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static	int	Initialized;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate extern	int	Retry;
58*0Sstevel@tonic-gate extern	struct	pollfd	*Pollp;
59*0Sstevel@tonic-gate static	void	initialize();
60*0Sstevel@tonic-gate static	void	open_all();
61*0Sstevel@tonic-gate static	int	set_poll();
62*0Sstevel@tonic-gate static	int	check_spawnlimit();
63*0Sstevel@tonic-gate static	int	mod_ttydefs();
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate void	open_device();
66*0Sstevel@tonic-gate void	set_softcar();
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate extern	int	check_session();
69*0Sstevel@tonic-gate extern	void	sigalarm();
70*0Sstevel@tonic-gate extern	void	revokedevaccess(char *, uid_t, gid_t, mode_t);
71*0Sstevel@tonic-gate /* can't include libdevinfo.h */
72*0Sstevel@tonic-gate extern int di_devperm_logout(const char *);
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * 	ttymon	- a port monitor under SAC
76*0Sstevel@tonic-gate  *		- monitor ports, set terminal modes, baud rate
77*0Sstevel@tonic-gate  *		  and line discipline for the port
78*0Sstevel@tonic-gate  *		- invoke service on port if connection request received
79*0Sstevel@tonic-gate  *		- Usage: ttymon
80*0Sstevel@tonic-gate  *			 ttymon -g [options]
81*0Sstevel@tonic-gate  *			 Valid options are
82*0Sstevel@tonic-gate  *			 -h
83*0Sstevel@tonic-gate  *			 -d device
84*0Sstevel@tonic-gate  *			 -l ttylabel
85*0Sstevel@tonic-gate  *			 -t timeout
86*0Sstevel@tonic-gate  *			 -m modules
87*0Sstevel@tonic-gate  *			 -p prompt
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  *		- ttymon without args is invoked by SAC
90*0Sstevel@tonic-gate  *		- ttymon -g is invoked by process that needs to
91*0Sstevel@tonic-gate  *		  have login service on the fly
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate main(argc, argv)
95*0Sstevel@tonic-gate int	argc;
96*0Sstevel@tonic-gate char	*argv[];
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	int	nfds;
99*0Sstevel@tonic-gate 	extern	char	*lastname();
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/*
102*0Sstevel@tonic-gate 	 * Only the superuser should execute this command.
103*0Sstevel@tonic-gate 	 */
104*0Sstevel@tonic-gate 	if (getuid() != 0)
105*0Sstevel@tonic-gate 		return (1);	/*NOTREACHED*/
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	if ((argc > 1) || (strcmp(lastname(argv[0]), "getty") == 0)) {
108*0Sstevel@tonic-gate 		ttymon_express(argc, argv);
109*0Sstevel@tonic-gate 		return (1);	/*NOTREACHED*/
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 	/* remember original signal mask and dispositions */
112*0Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, NULL, &Origmask);
113*0Sstevel@tonic-gate 	(void) sigaction(SIGINT, &Sigint, NULL);
114*0Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &Sigalrm, NULL);
115*0Sstevel@tonic-gate 	(void) sigaction(SIGPOLL, &Sigpoll, NULL);
116*0Sstevel@tonic-gate 	(void) sigaction(SIGCLD, &Sigcld, NULL);
117*0Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &Sigterm, NULL);
118*0Sstevel@tonic-gate #ifdef	DEBUG
119*0Sstevel@tonic-gate 	(void) sigaction(SIGUSR1, &Sigusr1, NULL);
120*0Sstevel@tonic-gate 	(void) sigaction(SIGUSR2, &Sigusr2, NULL);
121*0Sstevel@tonic-gate #endif
122*0Sstevel@tonic-gate 	initialize();
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	for (;;) {
125*0Sstevel@tonic-gate 		nfds = set_poll(Pollp);
126*0Sstevel@tonic-gate 		if (!Reread_flag) {
127*0Sstevel@tonic-gate 			if (nfds > 0)
128*0Sstevel@tonic-gate 				do_poll(Pollp, nfds);
129*0Sstevel@tonic-gate 			else
130*0Sstevel@tonic-gate 				(void) pause();
131*0Sstevel@tonic-gate 		}
132*0Sstevel@tonic-gate 		/*
133*0Sstevel@tonic-gate 		 * READDB messages may arrive during poll or pause.
134*0Sstevel@tonic-gate 		 * So the flag needs to be checked again.
135*0Sstevel@tonic-gate 		 */
136*0Sstevel@tonic-gate 		if (Reread_flag) {
137*0Sstevel@tonic-gate 			Reread_flag = FALSE;
138*0Sstevel@tonic-gate 			re_read();
139*0Sstevel@tonic-gate 		}
140*0Sstevel@tonic-gate 		while (Retry) {
141*0Sstevel@tonic-gate 			Retry = FALSE;
142*0Sstevel@tonic-gate 			open_all();
143*0Sstevel@tonic-gate 		}
144*0Sstevel@tonic-gate 	}
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate static	void
148*0Sstevel@tonic-gate initialize()
149*0Sstevel@tonic-gate {
150*0Sstevel@tonic-gate 	struct	pmtab	*tp;
151*0Sstevel@tonic-gate 	register struct passwd *pwdp;
152*0Sstevel@tonic-gate 	register struct	group	*gp;
153*0Sstevel@tonic-gate 	struct	rlimit rlimit;
154*0Sstevel@tonic-gate 	extern	struct	rlimit	Rlimit;
155*0Sstevel@tonic-gate 	extern	 uid_t	Uucp_uid;
156*0Sstevel@tonic-gate 	extern	 gid_t	Tty_gid;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate #ifdef 	DEBUG
159*0Sstevel@tonic-gate 	extern	opendebug();
160*0Sstevel@tonic-gate #endif
161*0Sstevel@tonic-gate 	Initialized = FALSE;
162*0Sstevel@tonic-gate 	/*
163*0Sstevel@tonic-gate 	 * get_environ() must be called first,
164*0Sstevel@tonic-gate 	 * otherwise we don't know where the log file is
165*0Sstevel@tonic-gate 	 */
166*0Sstevel@tonic-gate 	get_environ();
167*0Sstevel@tonic-gate 	openttymonlog();
168*0Sstevel@tonic-gate 	openpid();
169*0Sstevel@tonic-gate 	openpipes();
170*0Sstevel@tonic-gate 	setup_PCpipe();
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	log("PMTAG: %s", Tag);
173*0Sstevel@tonic-gate 	log("Starting state: %s",
174*0Sstevel@tonic-gate 	    (State == PM_ENABLED) ? "enabled" : "disabled");
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate #ifdef 	DEBUG
177*0Sstevel@tonic-gate 	opendebug(FALSE);
178*0Sstevel@tonic-gate 	debug("***** ttymon in initialize *****");
179*0Sstevel@tonic-gate 	log("debug mode is \t on");
180*0Sstevel@tonic-gate #endif
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	catch_signals();
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	/* register to receive SIGPOLL when data comes to pmpipe */
185*0Sstevel@tonic-gate 	if (ioctl(Pfd, I_SETSIG, S_INPUT) < 0)
186*0Sstevel@tonic-gate 		fatal("I_SETSIG on pmpipe failed: %s", strerror(errno));
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	sacpoll(); /* this is needed because there may be data already */
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	Maxfiles = (int)ulimit(4, 0L);	/* get max number of open files */
191*0Sstevel@tonic-gate 	if (Maxfiles < 0)
192*0Sstevel@tonic-gate 		fatal("ulimit(4,0L) failed: %s", strerror(errno));
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &Rlimit) == -1)
195*0Sstevel@tonic-gate 		fatal("getrlimit failed: %s", strerror(errno));
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	rlimit.rlim_cur = rlimit.rlim_max = Rlimit.rlim_max;
198*0Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rlimit) == -1)
199*0Sstevel@tonic-gate 		fatal("setrlimit failed: %s", strerror(errno));
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	Maxfiles = rlimit.rlim_cur;
202*0Sstevel@tonic-gate 	Maxfds = Maxfiles - FILE_RESERVED;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	log("max open files = %d", Maxfiles);
205*0Sstevel@tonic-gate 	log("max ports ttymon can monitor = %d", Maxfds);
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	read_pmtab();
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	/*
210*0Sstevel@tonic-gate 	 * setup poll array
211*0Sstevel@tonic-gate 	 * 	- we allocate 10 extra pollfd so that
212*0Sstevel@tonic-gate 	 *	  we do not have to re-malloc when there is
213*0Sstevel@tonic-gate 	 *	  minor fluctuation in Nentries
214*0Sstevel@tonic-gate 	 */
215*0Sstevel@tonic-gate 	Npollfd = Nentries + 10;
216*0Sstevel@tonic-gate 	if (Npollfd > Maxfds)
217*0Sstevel@tonic-gate 		Npollfd = Maxfds;
218*0Sstevel@tonic-gate 	if ((Pollp = (struct pollfd *)
219*0Sstevel@tonic-gate 	    malloc((unsigned)(Npollfd * sizeof (struct pollfd))))
220*0Sstevel@tonic-gate 	    == (struct pollfd *)NULL)
221*0Sstevel@tonic-gate 		fatal("malloc for Pollp failed");
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	(void) mod_ttydefs();	/* just to initialize Mtime */
224*0Sstevel@tonic-gate 	if (check_version(TTYDEFS_VERS, TTYDEFS) != 0)
225*0Sstevel@tonic-gate 		fatal("check /etc/ttydefs version failed");
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	read_ttydefs(NULL, FALSE);
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/* initialize global variables, Uucp_uid & Tty_gid */
230*0Sstevel@tonic-gate 	if ((pwdp = getpwnam(UUCP)) != NULL)
231*0Sstevel@tonic-gate 		Uucp_uid = pwdp->pw_uid;
232*0Sstevel@tonic-gate 	if ((gp = getgrnam(TTY)) == NULL)
233*0Sstevel@tonic-gate 		log("no group entry for <tty>, default is used");
234*0Sstevel@tonic-gate 	else
235*0Sstevel@tonic-gate 		Tty_gid = gp->gr_gid;
236*0Sstevel@tonic-gate 	endgrent();
237*0Sstevel@tonic-gate 	endpwent();
238*0Sstevel@tonic-gate #ifdef	DEBUG
239*0Sstevel@tonic-gate 	debug("Uucp_uid = %ld, Tty_gid = %ld", Uucp_uid, Tty_gid);
240*0Sstevel@tonic-gate #endif
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	log("Initialization Completed");
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	/* open the devices ttymon monitors */
245*0Sstevel@tonic-gate 	Retry = TRUE;
246*0Sstevel@tonic-gate 	while (Retry) {
247*0Sstevel@tonic-gate 		Retry = FALSE;
248*0Sstevel@tonic-gate 		for (tp = PMtab; tp; tp = tp->p_next) {
249*0Sstevel@tonic-gate 			if ((tp->p_status > 0) && (tp->p_fd == 0) &&
250*0Sstevel@tonic-gate 			    (tp->p_pid == 0) && !(tp->p_ttyflags & I_FLAG) &&
251*0Sstevel@tonic-gate 			    (!((State == PM_DISABLED) &&
252*0Sstevel@tonic-gate 			    ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) {
253*0Sstevel@tonic-gate 				open_device(tp);
254*0Sstevel@tonic-gate 				if (tp->p_fd > 0)
255*0Sstevel@tonic-gate 					got_carrier(tp);
256*0Sstevel@tonic-gate 			}
257*0Sstevel@tonic-gate 		}
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 	Initialized = TRUE;
260*0Sstevel@tonic-gate }
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate /*
263*0Sstevel@tonic-gate  *	open_all - open devices in pmtab if the entry is
264*0Sstevel@tonic-gate  *	         - valid, fd = 0, and pid = 0
265*0Sstevel@tonic-gate  */
266*0Sstevel@tonic-gate static void
267*0Sstevel@tonic-gate open_all()
268*0Sstevel@tonic-gate {
269*0Sstevel@tonic-gate 	struct	pmtab	*tp;
270*0Sstevel@tonic-gate 	int	check_modtime;
271*0Sstevel@tonic-gate 	static	void	free_defs();
272*0Sstevel@tonic-gate 	sigset_t cset;
273*0Sstevel@tonic-gate 	sigset_t tset;
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate #ifdef	DEBUG
276*0Sstevel@tonic-gate 	debug("in open_all");
277*0Sstevel@tonic-gate #endif
278*0Sstevel@tonic-gate 	check_modtime = TRUE;
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	for (tp = PMtab; tp; tp = tp->p_next) {
281*0Sstevel@tonic-gate 		if ((tp->p_status > 0) && (tp->p_fd == 0) &&
282*0Sstevel@tonic-gate 		    (tp->p_pid == 0) &&
283*0Sstevel@tonic-gate 		    !(tp->p_ttyflags & I_FLAG) && (!((State == PM_DISABLED) &&
284*0Sstevel@tonic-gate 		    ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) {
285*0Sstevel@tonic-gate 			/*
286*0Sstevel@tonic-gate 			 * if we have not check modification time and
287*0Sstevel@tonic-gate 			 * /etc/ttydefs was modified, need to re-read it
288*0Sstevel@tonic-gate 			 */
289*0Sstevel@tonic-gate 			if (check_modtime && mod_ttydefs()) {
290*0Sstevel@tonic-gate 				check_modtime = FALSE;
291*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, NULL, &cset);
292*0Sstevel@tonic-gate 				tset = cset;
293*0Sstevel@tonic-gate 				(void) sigaddset(&tset, SIGCLD);
294*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, &tset, NULL);
295*0Sstevel@tonic-gate 				free_defs();
296*0Sstevel@tonic-gate #ifdef	DEBUG
297*0Sstevel@tonic-gate 				debug("/etc/ttydefs is modified, re-read it");
298*0Sstevel@tonic-gate #endif
299*0Sstevel@tonic-gate 				read_ttydefs(NULL, FALSE);
300*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, &cset, NULL);
301*0Sstevel@tonic-gate 			}
302*0Sstevel@tonic-gate 			open_device(tp);
303*0Sstevel@tonic-gate 			if (tp->p_fd > 0)
304*0Sstevel@tonic-gate 				got_carrier(tp);
305*0Sstevel@tonic-gate 		} else if (((tp->p_status == LOCKED) ||
306*0Sstevel@tonic-gate 		    (tp->p_status == SESSION) ||
307*0Sstevel@tonic-gate 		    (tp->p_status == UNACCESS)) &&
308*0Sstevel@tonic-gate 		    (tp->p_fd > 0) &&
309*0Sstevel@tonic-gate 		    (!((State == PM_DISABLED) &&
310*0Sstevel@tonic-gate 		    ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) {
311*0Sstevel@tonic-gate 			if (check_modtime && mod_ttydefs()) {
312*0Sstevel@tonic-gate 				check_modtime = FALSE;
313*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, NULL, &cset);
314*0Sstevel@tonic-gate 				tset = cset;
315*0Sstevel@tonic-gate 				(void) sigaddset(&tset, SIGCLD);
316*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, &tset, NULL);
317*0Sstevel@tonic-gate 				free_defs();
318*0Sstevel@tonic-gate #ifdef	DEBUG
319*0Sstevel@tonic-gate 				debug("/etc/ttydefs is modified, re-read it");
320*0Sstevel@tonic-gate #endif
321*0Sstevel@tonic-gate 				read_ttydefs(NULL, FALSE);
322*0Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, &cset, NULL);
323*0Sstevel@tonic-gate 			}
324*0Sstevel@tonic-gate 			tp->p_status = VALID;
325*0Sstevel@tonic-gate 			open_device(tp);
326*0Sstevel@tonic-gate 			if (tp->p_fd > 0)
327*0Sstevel@tonic-gate 				got_carrier(tp);
328*0Sstevel@tonic-gate 		}
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate void
333*0Sstevel@tonic-gate set_softcar(pmptr)
334*0Sstevel@tonic-gate struct	pmtab	*pmptr;
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	int fd, val = 0;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate #ifdef	DEBUG
340*0Sstevel@tonic-gate 	debug("in set_softcar");
341*0Sstevel@tonic-gate #endif
342*0Sstevel@tonic-gate 	/*
343*0Sstevel@tonic-gate 	 * If soft carrier is not set one way or
344*0Sstevel@tonic-gate 	 * the other, leave it alone.
345*0Sstevel@tonic-gate 	 */
346*0Sstevel@tonic-gate 	if (*pmptr->p_softcar == '\0')
347*0Sstevel@tonic-gate 		return;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	if (*pmptr->p_softcar == 'y')
350*0Sstevel@tonic-gate 		val = 1;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	if ((fd = open(pmptr->p_device, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
353*0Sstevel@tonic-gate 		log("open (%s) failed: %s", pmptr->p_device, strerror(errno));
354*0Sstevel@tonic-gate 		return;
355*0Sstevel@tonic-gate 	}
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	if (ioctl(fd, TIOCSSOFTCAR, &val) < 0)
358*0Sstevel@tonic-gate 		log("set soft-carrier (%s) failed: %s", pmptr->p_device,
359*0Sstevel@tonic-gate 		    strerror(errno));
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	close(fd);
362*0Sstevel@tonic-gate }
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate /*
366*0Sstevel@tonic-gate  *	open_device(pmptr)	- open the device
367*0Sstevel@tonic-gate  *				- check device lock
368*0Sstevel@tonic-gate  *				- change owner of device
369*0Sstevel@tonic-gate  *				- push line disciplines
370*0Sstevel@tonic-gate  *				- set termio
371*0Sstevel@tonic-gate  */
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate void
374*0Sstevel@tonic-gate open_device(pmptr)
375*0Sstevel@tonic-gate struct	pmtab	*pmptr;
376*0Sstevel@tonic-gate {
377*0Sstevel@tonic-gate 	int	fd, tmpfd;
378*0Sstevel@tonic-gate 	struct	sigaction	sigact;
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate #ifdef	DEBUG
381*0Sstevel@tonic-gate 	debug("in open_device");
382*0Sstevel@tonic-gate #endif
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (pmptr->p_status == GETTY) {
385*0Sstevel@tonic-gate 		revokedevaccess(pmptr->p_device, 0, 0, 0);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 		if ((fd = open(pmptr->p_device, O_RDWR)) == -1)
388*0Sstevel@tonic-gate 			fatal("open (%s) failed: %s", pmptr->p_device,
389*0Sstevel@tonic-gate 			    strerror(errno));
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	} else {
392*0Sstevel@tonic-gate 		if (check_spawnlimit(pmptr) == -1) {
393*0Sstevel@tonic-gate 			pmptr->p_status = NOTVALID;
394*0Sstevel@tonic-gate 			log("service <%s> is respawning too rapidly",
395*0Sstevel@tonic-gate 			    pmptr->p_tag);
396*0Sstevel@tonic-gate 			return;
397*0Sstevel@tonic-gate 		}
398*0Sstevel@tonic-gate 		if (pmptr->p_fd > 0) { /* file already open */
399*0Sstevel@tonic-gate 			fd = pmptr->p_fd;
400*0Sstevel@tonic-gate 			pmptr->p_fd = 0;
401*0Sstevel@tonic-gate 		} else if ((fd = open(pmptr->p_device, O_RDWR|O_NONBLOCK))
402*0Sstevel@tonic-gate 		    == -1) {
403*0Sstevel@tonic-gate 			log("open (%s) failed: %s", pmptr->p_device,
404*0Sstevel@tonic-gate 			    strerror(errno));
405*0Sstevel@tonic-gate 			if ((errno ==  ENODEV) || (errno == EBUSY)) {
406*0Sstevel@tonic-gate 				pmptr->p_status = UNACCESS;
407*0Sstevel@tonic-gate 				Nlocked++;
408*0Sstevel@tonic-gate 				if (Nlocked == 1) {
409*0Sstevel@tonic-gate 				    sigact.sa_flags = 0;
410*0Sstevel@tonic-gate 				    sigact.sa_handler = sigalarm;
411*0Sstevel@tonic-gate 				    (void) sigemptyset(&sigact.sa_mask);
412*0Sstevel@tonic-gate 				    (void) sigaction(SIGALRM, &sigact, NULL);
413*0Sstevel@tonic-gate 				    (void) alarm(ALARMTIME);
414*0Sstevel@tonic-gate 				}
415*0Sstevel@tonic-gate 			} else
416*0Sstevel@tonic-gate 				Retry = TRUE;
417*0Sstevel@tonic-gate 			return;
418*0Sstevel@tonic-gate 		}
419*0Sstevel@tonic-gate 		/* set close-on-exec flag */
420*0Sstevel@tonic-gate 		if (fcntl(fd, F_SETFD, 1) == -1)
421*0Sstevel@tonic-gate 			fatal("F_SETFD fcntl failed: %s", strerror(errno));
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 		if (tm_checklock(fd) != 0) {
424*0Sstevel@tonic-gate 			pmptr->p_status = LOCKED;
425*0Sstevel@tonic-gate 			(void) close(fd);
426*0Sstevel@tonic-gate 			Nlocked++;
427*0Sstevel@tonic-gate 			if (Nlocked == 1) {
428*0Sstevel@tonic-gate 				sigact.sa_flags = 0;
429*0Sstevel@tonic-gate 				sigact.sa_handler = sigalarm;
430*0Sstevel@tonic-gate 				(void) sigemptyset(&sigact.sa_mask);
431*0Sstevel@tonic-gate 				(void) sigaction(SIGALRM, &sigact, NULL);
432*0Sstevel@tonic-gate 				(void) alarm(ALARMTIME);
433*0Sstevel@tonic-gate 			}
434*0Sstevel@tonic-gate 			return;
435*0Sstevel@tonic-gate 		}
436*0Sstevel@tonic-gate 		if (check_session(fd) != 0) {
437*0Sstevel@tonic-gate 			if ((Initialized) && (pmptr->p_inservice != SESSION)) {
438*0Sstevel@tonic-gate 				log("Warning -- active session exists on <%s>",
439*0Sstevel@tonic-gate 				    pmptr->p_device);
440*0Sstevel@tonic-gate 			} else {
441*0Sstevel@tonic-gate 				/*
442*0Sstevel@tonic-gate 				 * this may happen if a service is running
443*0Sstevel@tonic-gate 				 * and ttymon dies and is restarted,
444*0Sstevel@tonic-gate 				 * or another process is running on the
445*0Sstevel@tonic-gate 				 * port.
446*0Sstevel@tonic-gate 				 */
447*0Sstevel@tonic-gate 				pmptr->p_status = SESSION;
448*0Sstevel@tonic-gate 				pmptr->p_inservice = 0;
449*0Sstevel@tonic-gate 				(void) close(fd);
450*0Sstevel@tonic-gate 				Nlocked++;
451*0Sstevel@tonic-gate 				if (Nlocked == 1) {
452*0Sstevel@tonic-gate 					sigact.sa_flags = 0;
453*0Sstevel@tonic-gate 					sigact.sa_handler = sigalarm;
454*0Sstevel@tonic-gate 					(void) sigemptyset(&sigact.sa_mask);
455*0Sstevel@tonic-gate 					(void) sigaction(SIGALRM, &sigact,
456*0Sstevel@tonic-gate 					    NULL);
457*0Sstevel@tonic-gate 					(void) alarm(ALARMTIME);
458*0Sstevel@tonic-gate 				}
459*0Sstevel@tonic-gate 				return;
460*0Sstevel@tonic-gate 			}
461*0Sstevel@tonic-gate 		}
462*0Sstevel@tonic-gate 		pmptr->p_inservice = 0;
463*0Sstevel@tonic-gate 	}
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (pmptr->p_ttyflags & H_FLAG) {
466*0Sstevel@tonic-gate 		/* drop DTR */
467*0Sstevel@tonic-gate 		(void) hang_up_line(fd);
468*0Sstevel@tonic-gate 		/*
469*0Sstevel@tonic-gate 		 * After hang_up_line, the stream is in STRHUP state.
470*0Sstevel@tonic-gate 		 * We need to do another open to reinitialize streams
471*0Sstevel@tonic-gate 		 * then we can close one fd
472*0Sstevel@tonic-gate 		 */
473*0Sstevel@tonic-gate 		if ((tmpfd = open(pmptr->p_device, O_RDWR|O_NONBLOCK)) == -1) {
474*0Sstevel@tonic-gate 			log("open (%s) failed: %s", pmptr->p_device,
475*0Sstevel@tonic-gate 			    strerror(errno));
476*0Sstevel@tonic-gate 			Retry = TRUE;
477*0Sstevel@tonic-gate 			(void) close(fd);
478*0Sstevel@tonic-gate 			return;
479*0Sstevel@tonic-gate 		}
480*0Sstevel@tonic-gate 		(void) close(tmpfd);
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate #ifdef DEBUG
484*0Sstevel@tonic-gate 	debug("open_device (%s), fd = %d", pmptr->p_device, fd);
485*0Sstevel@tonic-gate #endif
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/* Change ownership of the tty line to root/uucp and */
488*0Sstevel@tonic-gate 	/* set protections to only allow root/uucp to read the line. */
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	if (pmptr->p_ttyflags & (B_FLAG|C_FLAG))
491*0Sstevel@tonic-gate 		(void) fchown(fd, Uucp_uid, Tty_gid);
492*0Sstevel@tonic-gate 	else
493*0Sstevel@tonic-gate 		(void) fchown(fd, ROOTUID, Tty_gid);
494*0Sstevel@tonic-gate 	(void) fchmod(fd, 0620);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	if ((pmptr->p_modules != NULL)&&(*(pmptr->p_modules) != '\0')) {
497*0Sstevel@tonic-gate 		if (push_linedisc(fd, pmptr->p_modules, pmptr->p_device)
498*0Sstevel@tonic-gate 		    == -1) {
499*0Sstevel@tonic-gate 			Retry = TRUE;
500*0Sstevel@tonic-gate 			(void) close(fd);
501*0Sstevel@tonic-gate 			return;
502*0Sstevel@tonic-gate 		}
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	if (initial_termio(fd, pmptr) == -1)  {
506*0Sstevel@tonic-gate 		Retry = TRUE;
507*0Sstevel@tonic-gate 		(void) close(fd);
508*0Sstevel@tonic-gate 		return;
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	di_devperm_logout((const char *)pmptr->p_device);
512*0Sstevel@tonic-gate 	pmptr->p_fd = fd;
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate /*
516*0Sstevel@tonic-gate  *	set_poll(fdp)	- put all fd's in a pollfd array
517*0Sstevel@tonic-gate  *			- set poll event to POLLIN and POLLMSG
518*0Sstevel@tonic-gate  *			- return number of fd to be polled
519*0Sstevel@tonic-gate  */
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate static	int
522*0Sstevel@tonic-gate set_poll(fdp)
523*0Sstevel@tonic-gate struct pollfd *fdp;
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	struct	pmtab	*tp;
526*0Sstevel@tonic-gate 	int 	nfd = 0;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	for (tp = PMtab; tp; tp = tp->p_next) {
529*0Sstevel@tonic-gate 		if (tp->p_fd > 0)  {
530*0Sstevel@tonic-gate 			fdp->fd = tp->p_fd;
531*0Sstevel@tonic-gate 			fdp->events = POLLIN;
532*0Sstevel@tonic-gate 			fdp++;
533*0Sstevel@tonic-gate 			nfd++;
534*0Sstevel@tonic-gate 		}
535*0Sstevel@tonic-gate 	}
536*0Sstevel@tonic-gate 	return (nfd);
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate /*
540*0Sstevel@tonic-gate  *	check_spawnlimit	- return 0 if spawnlimit is not reached
541*0Sstevel@tonic-gate  *				- otherwise return -1
542*0Sstevel@tonic-gate  */
543*0Sstevel@tonic-gate static	int
544*0Sstevel@tonic-gate check_spawnlimit(pmptr)
545*0Sstevel@tonic-gate struct	pmtab	*pmptr;
546*0Sstevel@tonic-gate {
547*0Sstevel@tonic-gate 	time_t	now;
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	(void) time(&now);
550*0Sstevel@tonic-gate 	if (pmptr->p_time == 0L)
551*0Sstevel@tonic-gate 		pmptr->p_time = now;
552*0Sstevel@tonic-gate 	if (pmptr->p_respawn >= SPAWN_LIMIT) {
553*0Sstevel@tonic-gate 		if ((now - pmptr->p_time) < SPAWN_INTERVAL) {
554*0Sstevel@tonic-gate 			pmptr->p_time = now;
555*0Sstevel@tonic-gate 			pmptr->p_respawn = 0;
556*0Sstevel@tonic-gate 			return (-1);
557*0Sstevel@tonic-gate 		}
558*0Sstevel@tonic-gate 		pmptr->p_time = now;
559*0Sstevel@tonic-gate 		pmptr->p_respawn = 0;
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 	pmptr->p_respawn++;
562*0Sstevel@tonic-gate 	return (0);
563*0Sstevel@tonic-gate }
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate /*
566*0Sstevel@tonic-gate  * mod_ttydefs	- to check if /etc/ttydefs has been modified
567*0Sstevel@tonic-gate  *		- return TRUE if file modified
568*0Sstevel@tonic-gate  *		- otherwise, return FALSE
569*0Sstevel@tonic-gate  */
570*0Sstevel@tonic-gate static	int
571*0Sstevel@tonic-gate mod_ttydefs()
572*0Sstevel@tonic-gate {
573*0Sstevel@tonic-gate 	struct	stat	statbuf;
574*0Sstevel@tonic-gate 	extern	long	Mtime;
575*0Sstevel@tonic-gate 	if (stat(TTYDEFS, &statbuf) == -1) {
576*0Sstevel@tonic-gate 		/* if stat failed, don't bother reread ttydefs */
577*0Sstevel@tonic-gate 		return (FALSE);
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 	if ((long)statbuf.st_mtime != Mtime) {
580*0Sstevel@tonic-gate 		Mtime = (long)statbuf.st_mtime;
581*0Sstevel@tonic-gate 		return (TRUE);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	return (FALSE);
584*0Sstevel@tonic-gate }
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate /*
587*0Sstevel@tonic-gate  *	free_defs - free the Gdef table
588*0Sstevel@tonic-gate  */
589*0Sstevel@tonic-gate static	void
590*0Sstevel@tonic-gate free_defs()
591*0Sstevel@tonic-gate {
592*0Sstevel@tonic-gate 	int	i;
593*0Sstevel@tonic-gate 	struct	Gdef	*tp;
594*0Sstevel@tonic-gate 	tp = &Gdef[0];
595*0Sstevel@tonic-gate 	for (i = 0; i < Ndefs; i++, tp++) {
596*0Sstevel@tonic-gate 		free(tp->g_id);
597*0Sstevel@tonic-gate 		free(tp->g_iflags);
598*0Sstevel@tonic-gate 		free(tp->g_fflags);
599*0Sstevel@tonic-gate 		free(tp->g_nextid);
600*0Sstevel@tonic-gate 		tp->g_id = NULL;
601*0Sstevel@tonic-gate 		tp->g_iflags = NULL;
602*0Sstevel@tonic-gate 		tp->g_fflags = NULL;
603*0Sstevel@tonic-gate 		tp->g_nextid = NULL;
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate 	Ndefs = 0;
606*0Sstevel@tonic-gate }
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate /*
609*0Sstevel@tonic-gate  * struct Gdef *get_speed(ttylabel)
610*0Sstevel@tonic-gate  *	- search "/etc/ttydefs" for speed and term. specification
611*0Sstevel@tonic-gate  *	  using "ttylabel". If "ttylabel" is NULL, default
612*0Sstevel@tonic-gate  *	  to DEFAULT
613*0Sstevel@tonic-gate  * arg:	  ttylabel - label/id of speed settings.
614*0Sstevel@tonic-gate  */
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate struct Gdef *
617*0Sstevel@tonic-gate get_speed(char *ttylabel)
618*0Sstevel@tonic-gate {
619*0Sstevel@tonic-gate 	register struct Gdef *sp;
620*0Sstevel@tonic-gate 	extern   struct Gdef DEFAULT;
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	if ((ttylabel != NULL) && (*ttylabel != '\0')) {
623*0Sstevel@tonic-gate 		if ((sp = find_def(ttylabel)) == NULL) {
624*0Sstevel@tonic-gate 			log("unable to find <%s> in \"%s\"", ttylabel, TTYDEFS);
625*0Sstevel@tonic-gate 			sp = &DEFAULT; /* use default */
626*0Sstevel@tonic-gate 		}
627*0Sstevel@tonic-gate 	} else sp = &DEFAULT; /* use default */
628*0Sstevel@tonic-gate 	return (sp);
629*0Sstevel@tonic-gate }
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate /*
632*0Sstevel@tonic-gate  * setup_PCpipe()	- setup the pipe between Parent and Children
633*0Sstevel@tonic-gate  *			- the pipe is used for a tmchild to send its
634*0Sstevel@tonic-gate  *			  pid to inform ttymon that it is about to
635*0Sstevel@tonic-gate  *			  invoke service
636*0Sstevel@tonic-gate  *			- the pipe also serves as a mean for tmchild
637*0Sstevel@tonic-gate  *			  to detect failure of ttymon
638*0Sstevel@tonic-gate  */
639*0Sstevel@tonic-gate void
640*0Sstevel@tonic-gate setup_PCpipe()
641*0Sstevel@tonic-gate {
642*0Sstevel@tonic-gate 	int	flag = 0;
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	if (pipe(PCpipe) == -1)
645*0Sstevel@tonic-gate 		fatal("pipe() failed: %s", strerror(errno));
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/* set close-on-exec flag */
648*0Sstevel@tonic-gate 	if (fcntl(PCpipe[0], F_SETFD, 1) == -1)
649*0Sstevel@tonic-gate 		fatal("F_SETFD fcntl failed: %s", strerror(errno));
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	if (fcntl(PCpipe[1], F_SETFD, 1) == -1)
652*0Sstevel@tonic-gate 		fatal("F_SETFD fcntl failed: %s", strerror(errno));
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	/* set O_NONBLOCK flag */
655*0Sstevel@tonic-gate 	if (fcntl(PCpipe[0], F_GETFL, flag) == -1)
656*0Sstevel@tonic-gate 		fatal("F_GETFL failed: %s", strerror(errno));
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	flag |= O_NONBLOCK;
659*0Sstevel@tonic-gate 	if (fcntl(PCpipe[0], F_SETFL, flag) == -1)
660*0Sstevel@tonic-gate 		fatal("F_SETFL failed: %s", strerror(errno));
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	/* set message discard mode */
663*0Sstevel@tonic-gate 	if (ioctl(PCpipe[0], I_SRDOPT, RMSGD) == -1)
664*0Sstevel@tonic-gate 		fatal("I_SRDOPT RMSGD failed: %s", strerror(errno));
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	/* register to receive SIGPOLL when data come */
667*0Sstevel@tonic-gate 	if (ioctl(PCpipe[0], I_SETSIG, S_INPUT) == -1)
668*0Sstevel@tonic-gate 		fatal("I_SETSIG S_INPUT failed: %s", strerror(errno));
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate #ifdef 	DEBUG
671*0Sstevel@tonic-gate 	log("PCpipe[0]\t = %d", PCpipe[0]);
672*0Sstevel@tonic-gate 	log("PCpipe[1]\t = %d", PCpipe[1]);
673*0Sstevel@tonic-gate #endif
674*0Sstevel@tonic-gate }
675