4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
41 #include <sys/types.h>
42 #include <sys/stropts.h>
51 static struct pmtab
*find_pid();
52 static void kill_children();
54 static struct pmtab
*find_fd();
55 static void pcsync_close();
56 extern void sigalarm();
57 extern void tmchild();
60 * fork_tmchild - fork child on the device
69 int pcpipe0
[2], pcpipe1
[2];
73 debug("in fork_tmchild");
75 pmptr
->p_inservice
= FALSE
;
79 * Child has pcpipe[0] pipe fd for reading and writing
80 * and closes pcpipe[1]. Parent has pcpipe[1] pipe fd for
81 * reading and writing and closes pcpipe[0].
83 * This way if the child process exits the parent's block
84 * read on pipe will return immediately as the other end of
85 * the pipe has closed. Similarly if the parent process exits
86 * child's blocking read on the pipe will return immediately.
89 if (((p0
= pipe(pcpipe0
)) == -1) || (pipe(pcpipe1
) == -1)) {
94 log("pipe() failed: %s", strerror(errno
));
95 pmptr
->p_status
= VALID
;
100 /* protect following region from SIGCLD */
101 (void)sigprocmask(SIG_SETMASK
, NULL
, &cset
);
103 (void)sigaddset(&tset
, SIGCLD
);
104 (void)sigprocmask(SIG_SETMASK
, &tset
, NULL
);
105 if( (pid
=fork()) == 0 ) {
107 * Close all file descriptors except pmptr->p_fd
108 * Wait for the parent process to close its fd
110 pcsync_close(pcpipe0
, pcpipe1
, pid
, pmptr
->p_fd
);
113 /* tmchild should never return */
114 fatal("tmchild for <%s> returns unexpected", pmptr
->p_device
);
117 log("fork failed: %s", strerror(errno
));
118 pmptr
->p_status
= VALID
;
124 * The PARENT - store pid of child and close the device
128 if (pmptr
->p_fd
> 0) {
129 (void)close(pmptr
->p_fd
);
132 (void)sigprocmask(SIG_SETMASK
, &cset
, NULL
);
134 * Wait for child to close file descriptors
136 pcsync_close(pcpipe0
, pcpipe1
, pid
, pmptr
->p_fd
);
140 * got_carrier - carrier is detected on the stream
141 * - depends on the flags, different action is taken
142 * - R_FLAG - wait for data
143 * - C_FLAG - if port is not disabled, fork tmchild
144 * - A_FLAG - wait for data
145 * - otherwise - write out prompt, then wait for data
151 flush_input(pmptr
->p_fd
);
153 if (pmptr
->p_ttyflags
& R_FLAG
) {
159 else if ((pmptr
->p_ttyflags
& (C_FLAG
|B_FLAG
)) &&
160 (State
!= PM_DISABLED
) &&
161 (!(pmptr
->p_flags
& X_FLAG
))) {
164 else if (pmptr
->p_ttyflags
& A_FLAG
) {
170 else if (pmptr
->p_timeout
) {
173 else if ( ! (pmptr
->p_ttyflags
& X_FLAG
) ) {
174 write_prompt(pmptr
->p_fd
,pmptr
,TRUE
,TRUE
);
179 * got_data - data is detected on the stream, fork tmchild
185 struct sigaction sigact
;
187 if (tm_checklock(pmptr
->p_fd
) != 0) {
188 pmptr
->p_status
= LOCKED
;
189 (void)close(pmptr
->p_fd
);
194 sigact
.sa_handler
= sigalarm
;
195 (void)sigemptyset(&sigact
.sa_mask
);
196 (void)sigaction(SIGALRM
, &sigact
, NULL
);
197 (void)alarm(ALARMTIME
);
204 * got_hup - stream hangup is detected, close the device
213 (void)close(pmptr
->p_fd
);
215 pmptr
->p_inservice
= 0;
221 * do_poll - poll device
222 * - if POLLHUP received, close the device
223 * - if POLLIN received, fork tmchild.
233 n
= poll(fdp
, (unsigned long)nfds
, -1); /* blocked poll */
235 debug("poll return");
238 if (errno
== EINTR
) /* interrupt by signal */
240 fatal("do_poll: poll failed: %s", strerror(errno
));
242 for (i
= 0; (i
< nfds
)&&(n
); i
++,fdp
++) {
243 if (fdp
->revents
!= 0) {
245 if ((pmptr
= find_fd(fdp
->fd
)) == NULL
) {
246 log("do_poll: cannot find fd %d in pmtab",
250 else if (fdp
->revents
& POLLHUP
) {
253 else if (fdp
->revents
& POLLIN
) {
258 } else if (fdp
->revents
& POLLERR
) {
259 fatal("ttymon[%d]: do_poll: POLLERR on fd %d",
267 * sigchild - handler for SIGCLD
268 * - find the pid of dead child
269 * - clean utmp if U_FLAG is set
274 int n
; /* this is declared to make cc happy, but it is not used */
277 struct sigaction sigact
;
284 debug("in sigchild");
287 /* find all processes that died */
289 rcode
= waitid(P_ALL
, 0, &info
, WNOHANG
|WEXITED
);
290 if (rcode
== -1 && errno
== EINTR
)
293 /* If no more children have exited, just return */
294 if (rcode
== -1 || (pid
= info
.si_pid
) == 0)
297 /* construct status as returned from waitid() */
298 status
= info
.si_status
& 0377;
299 switch (info
.si_code
) {
310 if ((pmptr
= find_pid(pid
)) == NULL
) {
312 log("cannot find dead child (%ld) in pmtab", pid
);
315 * This may happen if the entry is deleted from pmtab
316 * before the service exits.
317 * We try to cleanup utmp entry
319 cleanut(pid
, status
);
321 if (pmptr
->p_flags
& U_FLAG
)
322 cleanut(pid
, status
);
323 pmptr
->p_status
= VALID
;
326 pmptr
->p_inservice
= 0;
333 * sigterm - handler for SIGTERM
338 fatal("caught SIGTERM");
342 * state_change - this is called when ttymon changes
343 * its internal state between enabled and disabled
351 debug("in state_change");
355 * closing PCpipe will cause attached non-service children
356 * to get SIGPOLL and exit
358 (void)close(PCpipe
[0]);
359 (void)close(PCpipe
[1]);
365 * also close all open ports so ttymon can start over
366 * with new internal state
368 for (pmptr
= PMtab
; pmptr
; pmptr
= pmptr
->p_next
) {
369 if ((pmptr
->p_fd
> 0) && (pmptr
->p_pid
== 0)) {
370 (void)close(pmptr
->p_fd
);
379 * re_read - reread pmtab
380 * - kill tmchild if entry changed
385 extern struct pollfd
*Pollp
;
389 (void)sigprocmask(SIG_SETMASK
, NULL
, &cset
);
391 (void)sigaddset(&tset
, SIGCLD
);
392 (void)sigprocmask(SIG_SETMASK
, &tset
, NULL
);
399 (void)sigprocmask(SIG_SETMASK
, &cset
, NULL
);
402 if (Nentries
> Npollfd
) {
404 debug("Nentries > Npollfd, reallocating pollfds");
406 /* need to malloc more pollfd structure */
408 Npollfd
= Nentries
+ 10;
409 if (Npollfd
> Maxfds
)
411 if ((Pollp
= (struct pollfd
*)
412 malloc((unsigned)(Npollfd
* sizeof(struct pollfd
))))
413 == (struct pollfd
*)NULL
)
414 fatal("malloc for Pollp failed");
420 * find_pid(pid) - find the corresponding pmtab entry for the pid
422 static struct pmtab
*
428 for (pmptr
= PMtab
; pmptr
; pmptr
= pmptr
->p_next
) {
429 if (pmptr
->p_pid
== pid
) {
433 return((struct pmtab
*)NULL
);
437 * find_fd(fd) - find the corresponding pmtab entry for the fd
439 static struct pmtab
*
445 for (pmptr
= PMtab
; pmptr
; pmptr
= pmptr
->p_next
) {
446 if (pmptr
->p_fd
== fd
) {
450 return((struct pmtab
*)NULL
);
454 * kill_children() - if the pmtab entry has been changed,
455 * kill tmchild if it is not in service.
456 * - close the device if there is no tmchild
462 for (pmptr
= PMtab
; pmptr
; pmptr
= pmptr
->p_next
) {
463 if (pmptr
->p_status
== VALID
)
465 if ((pmptr
->p_fd
> 0) && (pmptr
->p_pid
== 0)) {
466 (void)close(pmptr
->p_fd
);
469 else if ((pmptr
->p_fd
== 0) && (pmptr
->p_pid
> 0)
470 && (pmptr
->p_inservice
== FALSE
)) {
471 (void)kill(pmptr
->p_pid
, SIGTERM
);
482 debug("in mark_service");
484 if ((pmptr
= find_pid(pid
)) == NULL
) {
485 log("mark_service: cannot find child (%ld) in pmtab", pid
);
488 pmptr
->p_inservice
= TRUE
;
493 * read_pid(fd) - read pid info from PCpipe
503 if ((ret
= read(fd
,&pid
,sizeof(pid
))) < 0) {
508 fatal("read PCpipe failed: %s", strerror(errno
));
512 if (ret
!= sizeof(pid
))
513 fatal("read return size incorrect, ret = %d", ret
);
520 * sipoll_catch() - signal handle of SIGPOLL for ttymon
521 * - it will check both PCpipe and pmpipe
527 struct pollfd pfd
[2];
530 debug("in sigpoll_catch");
533 pfd
[0].fd
= PCpipe
[0];
535 pfd
[0].events
= POLLIN
;
536 pfd
[1].events
= POLLIN
;
537 if ((ret
= poll(pfd
, 2, 0)) < 0)
538 fatal("sigpoll_catch: poll failed: %s", strerror(errno
));
541 if (pfd
[0].revents
& POLLIN
)
543 if (pfd
[1].revents
& POLLIN
)
554 struct sigaction sigact
;
556 extern int check_session();
559 debug("in sigalarm, Nlocked = %d", Nlocked
);
561 for (pmptr
= PMtab
; pmptr
; pmptr
= pmptr
->p_next
) {
562 if ((pmptr
->p_status
== LOCKED
) && (pmptr
->p_fd
== 0)) {
563 if ((fd
=open(pmptr
->p_device
,O_RDWR
|O_NONBLOCK
)) == -1){
564 log("open (%s) failed: %s", pmptr
->p_device
,
566 pmptr
->p_status
= VALID
;
571 if (tm_checklock(fd
) == 0) {
580 else if ((pmptr
->p_status
== SESSION
) && (pmptr
->p_fd
== 0)) {
581 if ((fd
=open(pmptr
->p_device
,O_RDWR
|O_NONBLOCK
)) == -1){
582 log("open (%s) failed: %s", pmptr
->p_device
,
584 pmptr
->p_status
= VALID
;
589 if (check_session(fd
) == 0) {
598 else if ((pmptr
->p_status
== UNACCESS
) && (pmptr
->p_fd
== 0)) {
599 if ((fd
=open(pmptr
->p_device
,O_RDWR
|O_NONBLOCK
)) == -1){
600 log("open (%s) failed: %s", pmptr
->p_device
,
602 pmptr
->p_status
= VALID
;
615 sigact
.sa_handler
= sigalarm
;
616 (void)sigemptyset(&sigact
.sa_mask
);
617 (void)sigaction(SIGALRM
, &sigact
, NULL
);
618 (void)alarm(ALARMTIME
);
622 sigact
.sa_handler
= SIG_IGN
;
623 (void)sigemptyset(&sigact
.sa_mask
);
624 (void)sigaction(SIGALRM
, &sigact
, NULL
);
629 * pcsync_close - For the child process close all open fd's except
630 * the one that is passed to the routine. Coordinate the reads and
631 * writes to the pipes by the parent and child process to ensure
632 * the parent and child processes have closed all the file descriptors
633 * that are not needed any more.
636 pcsync_close(p0
, p1
, pid
, fd
)
643 if (pid
== 0) { /* Child */
645 for (tp
= PMtab
; tp
; tp
= tp
->p_next
)
646 if ((tp
->p_fd
> 0) && (tp
->p_fd
!= fd
))
648 close(p0
[1]); close(p1
[0]);
649 if (read(p0
[0], &ch
, 1) == 1)
650 write(p1
[1], "a", 1);
651 close(p0
[0]); close(p1
[1]);
652 } else { /* Parent */
653 close(p0
[0]); close(p1
[1]);
654 if (write(p0
[1], "a", 1) == 1)
656 close(p0
[1]); close(p1
[0]);