4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
33 #include <sys/types.h>
39 #include "sys/stropts.h"
40 #include <sys/resource.h>
46 #include <sys/utsname.h>
49 static void openline();
50 static void invoke_service();
51 static char *do_autobaud();
52 static struct Gdef
*next_speed();
53 static int check_hup();
55 extern struct Gdef
*get_speed();
56 extern struct strbuf
*peek_ptr
, *do_peek();
59 * tmchild - process that handles peeking data, determine baud rate
60 * and invoke service on each individual port.
67 register struct Gdef
*speedef
;
68 char *auto_speed
= "";
69 struct sigaction sigact
;
75 if (pmtab
->p_status
!= GETTY
) {
77 (void) close(PCpipe
[0]); /* close parent end of the pipe */
78 if (ioctl(PCpipe
[1], I_SETSIG
, S_HANGUP
) == -1) {
79 log("I_SETSIG failed: %s", strerror(errno
));
83 * the following check is to make sure no hangup
84 * happens before registering for SIGPOLL
86 if (check_hup(PCpipe
[1])) {
88 debug("PCpipe hungup, tmchild exiting");
93 if (pmtab
->p_ttyflags
& (C_FLAG
|B_FLAG
)) {
94 if (pmtab
->p_fd
> 0) {
95 (void) close(pmtab
->p_fd
);
101 * become the session leader so that a controlling tty
106 speedef
= get_speed(pmtab
->p_ttylabel
);
107 openline(pmtab
, speedef
);
108 if (pmtab
->p_ttyflags
& (C_FLAG
|B_FLAG
)) {
109 if (pmtab
->p_fd
>= 0) {
110 if ((pmtab
->p_modules
!= NULL
)&&(*(pmtab
->p_modules
) != '\0')) {
111 if (push_linedisc(pmtab
->p_fd
, pmtab
->p_modules
, pmtab
->p_device
) == -1) {
112 (void) close(pmtab
->p_fd
);
118 if ((pmtab
->p_ttyflags
& C_FLAG
) &&
119 (State
!= PM_DISABLED
) &&
120 (!(pmtab
->p_flags
& X_FLAG
))) {
122 * if "c" flag is set, and the port is not disabled
123 * invoke service immediately
125 if (set_termio(0, speedef
->g_fflags
, NULL
,FALSE
,CANON
) == -1) {
126 log("set final termio failed");
129 invoke_service(pmtab
);
130 exit(1); /*NOTREACHED*/
132 if (speedef
->g_autobaud
& A_FLAG
) {
133 auto_speed
= do_autobaud(pmtab
, speedef
);
135 if (set_termio(0, speedef
->g_fflags
, NULL
, FALSE
, CANON
) == -1) {
136 log("set final termio failed");
139 if ((pmtab
->p_ttyflags
& (R_FLAG
|A_FLAG
)) ||
140 (pmtab
->p_status
== GETTY
) || (pmtab
->p_timeout
> 0)) {
141 write_prompt(1, pmtab
, TRUE
, TRUE
);
142 if (pmtab
->p_timeout
) {
144 sigact
.sa_handler
= timedout
;
145 (void) sigemptyset(&sigact
.sa_mask
);
146 (void) sigaction(SIGALRM
, &sigact
, NULL
);
147 (void) alarm((unsigned)pmtab
->p_timeout
);
150 else if ((pmtab
->p_ttyflags
& (B_FLAG
)))
151 write_prompt(pmtab
->p_fd
, pmtab
, TRUE
, TRUE
);
154 /* Loop until user is successful in invoking service. */
157 /* Peek the user's typed response and respond appropriately. */
158 switch (poll_data()) {
161 debug("got GOODNAME");
163 if (pmtab
->p_timeout
) {
164 (void) alarm((unsigned)0);
166 sigact
.sa_handler
= SIG_DFL
;
167 (void) sigemptyset(&sigact
.sa_mask
);
168 (void) sigaction(SIGALRM
, &sigact
, NULL
);
170 if ((State
== PM_DISABLED
)||(pmtab
->p_flags
& X_FLAG
)){
171 write_prompt(1, pmtab
, TRUE
, FALSE
);
174 if (set_termio(0, speedef
->g_fflags
, auto_speed
,
175 FALSE
, CANON
) == -1) {
176 log("set final termio failed");
179 invoke_service(pmtab
);
180 exit(1); /*NOTREACHED*/
183 /* wrong speed! try next speed in the list. */
184 speedef
= next_speed(speedef
);
186 debug("BADSPEED: setup next speed");
188 if (speedef
->g_autobaud
& A_FLAG
) {
189 if (auto_termio(0) == -1) {
192 auto_speed
= do_autobaud(pmtab
, speedef
);
197 * this reset may fail if the speed is not
198 * supported by the system
199 * we just cycle through it to the next one
201 if (set_termio(0, speedef
->g_iflags
, NULL
,
202 FALSE
, CANON
) != 0) {
203 log("Warning -- speed of <%s> may "
204 "be not supported by the system",
208 write_prompt(1, pmtab
, TRUE
, TRUE
);
215 write_prompt(1, pmtab
, FALSE
, FALSE
);
221 if (pmtab
->p_timeout
) {
223 sigact
.sa_handler
= timedout
;
224 (void) sigemptyset(&sigact
.sa_mask
);
225 (void) sigaction(SIGALRM
, &sigact
, NULL
);
226 (void) alarm((unsigned)pmtab
->p_timeout
);
232 openline(pmtab
, speedef
)
234 struct Gdef
*speedef
;
241 debug("in openline");
243 if (pmtab
->p_status
!= GETTY
) {
245 /* open should return fd 0, if not, then close it */
246 if ((pmtab
->p_fd
= open(pmtab
->p_device
, O_RDWR
)) != 0) {
247 log("open \"%s\" failed: %s", pmtab
->p_device
,
257 if (pmtab
->p_ttyflags
& R_FLAG
) { /* wait_read is needed */
258 if (pmtab
->p_count
) {
259 if (peek_ptr
!= NULL
)
260 if ((peek_ptr
->buf
[0]&0x7F) == '\n' ||
261 (peek_ptr
->buf
[0]&0x7F) == '\r')
265 * - wait for "p_count" lines
266 * - datakit switch does not
267 * know you are a host or a terminal
268 * - so it send you several lines of msg
269 * - we need to swallow that msg
270 * - we assume the baud rate is correct
271 * - if it is not, '\n' will not look like '\n'
272 * and we will wait forever here
274 if (set_termio(0, speedef
->g_fflags
, NULL
, TRUE
, CANON
) == -1) {
275 log("set final termio failed");
278 for (line_count
= 0; line_count
< pmtab
->p_count
; ) {
279 if (read(0, buffer
, 1) < 0
281 || *buffer
== '\004') {
289 else { /* wait for 1 char */
290 if (peek_ptr
== NULL
) {
291 if (set_termio(0, NULL
, NULL
,TRUE
,RAW
) == -1) {
292 log("set termio RAW failed");
295 rtn
= read(0, buffer
, 1);
297 *buffer
= (peek_ptr
->buf
[0]&0x7F);
300 * NOTE: Cu on a direct line when ~. is encountered will
301 * send EOTs to the other side. EOT=\004
303 if (rtn
< 0 || *buffer
== '\004') {
309 if (!(pmtab
->p_ttyflags
& A_FLAG
)) { /* autobaud not enabled */
310 if (set_termio(0, speedef
->g_fflags
, NULL
, TRUE
, CANON
) == -1) {
311 log("set final termio failed");
316 if (pmtab
->p_ttyflags
& B_FLAG
) { /* port is bi-directional */
317 /* set advisory lock on the line */
318 if (tm_lock(0) != 0) {
321 * child exits and let the parent wait for
322 * the lock to go away
326 /* change ownership back to root */
327 (void) fchown(0, ROOTUID
, Tty_gid
);
328 (void) fchmod(0, 0620);
334 * write_prompt - write the msg to fd
335 * - if flush is set, flush input queue
336 * - if clear is set, write a new line
339 write_prompt(fd
, pmtab
, flush
, clear
)
346 debug("in write_prompt");
351 (void) write(fd
, "\r\n", 2);
356 /* Print prompt/disable message. */
357 if ((State
== PM_DISABLED
) || (pmtab
->p_flags
& X_FLAG
))
358 (void)write(fd
, pmtab
->p_dmsg
, (unsigned)strlen(pmtab
->p_dmsg
));
360 (void) write(fd
, pmtab
->p_prompt
,
361 (unsigned)strlen(pmtab
->p_prompt
));
365 * timedout - input period timed out
375 * void sys_name() - generate a msg with system id
376 * - print out /etc/issue file if it exists
382 char *ptr
, buffer
[BUFSIZ
];
385 #if 0 /* 1111333 - don't print node name, we already do this elsewhere */
386 struct utsname utsname
;
388 if (uname(&utsname
) != FAILURE
) {
389 (void) sprintf(buffer
, "%.9s\r\n", utsname
.nodename
);
390 (void) write(fd
, buffer
, strlen(buffer
));
394 if ((fp
= fopen(ISSUEFILE
, "r")) != NULL
) {
395 while ((ptr
= fgets(buffer
, sizeof (buffer
), fp
)) != NULL
) {
396 (void) write(fd
, ptr
, strlen(ptr
));
405 * do_autobaud - do autobaud
406 * - if it succeed, set the new speed and return
407 * - if it failed, it will get the nextlabel
408 * - if next entry is also autobaud,
409 * it will loop back to do autobaud again
410 * - otherwise, it will set new termio and return
413 do_autobaud(pmtab
, speedef
)
415 struct Gdef
*speedef
;
420 debug("in do_autobaud");
423 if ((auto_speed
= autobaud(0, pmtab
->p_timeout
)) == NULL
) {
424 speedef
= next_speed(speedef
);
425 if (speedef
->g_autobaud
& A_FLAG
) {
429 if (set_termio(0, speedef
->g_iflags
, NULL
,
437 if (set_termio(0, speedef
->g_fflags
, auto_speed
,
445 debug("autobaud done");
451 * next_speed(speedef)
452 * - find the next entry according to nextlabel. If "nextlabel"
453 * is not valid, go back to the old ttylabel.
458 struct Gdef
*speedef
;
462 if (strcmp(speedef
->g_nextid
, speedef
->g_id
) == 0)
464 if ((sp
= find_def(speedef
->g_nextid
)) == NULL
) {
465 log("%s's next speed-label (%s) is bad.", speedef
->g_id
,
468 /* go back to the original entry. */
469 if ((sp
= find_def(speedef
->g_id
)) == NULL
) {
470 /* if failed, complain and quit. */
471 log("unable to find (%s) again", speedef
->g_id
);
479 * inform_parent() - inform ttymon that tmchild is going to exec service
488 (void) write(fd
, &pid
, sizeof (pid
));
491 static char pbuf
[BUFSIZ
]; /* static buf for TTYPROMPT */
492 static char hbuf
[BUFSIZ
]; /* static buf for HOME */
493 static char tbuf
[BUFSIZ
]; /* static buf for TERM */
496 * void invoke_service - invoke the service
500 invoke_service(pmtab
)
503 char *argvp
[MAXARGS
]; /* service cmd args */
504 int cnt
= 0; /* arg counter */
506 struct sigaction sigact
;
507 extern struct rlimit Rlimit
;
510 debug("in invoke_service");
513 if (tcgetsid(0) != getsid(getpid())) {
514 cons_printf("Warning -- ttymon cannot allocate controlling "
515 "tty on \"%s\",\n", pmtab
->p_device
);
516 cons_printf("\tThere may be another session active on this "
519 if (strcmp("/dev/console", pmtab
->p_device
) != 0) {
521 * if not on console, write to stderr to warn the user
524 (void) fprintf(stderr
, "Warning -- ttymon cannot "
525 "allocate controlling tty on \"%s\",\n",
527 (void) fprintf(stderr
, "\tthere may be another session "
528 "active on this port.\n");
532 if (pmtab
->p_status
!= GETTY
) {
533 inform_parent(PCpipe
[1]);
535 sigact
.sa_handler
= SIG_DFL
;
536 (void) sigemptyset(&sigact
.sa_mask
);
537 (void) sigaction(SIGPOLL
, &sigact
, NULL
);
540 if (pmtab
->p_flags
& U_FLAG
) {
541 if (account(pmtab
->p_device
) != 0) {
542 log("invoke_service: account failed");
547 /* parse command line */
548 mkargv(pmtab
->p_server
, &argvp
[0], &cnt
, MAXARGS
-1);
550 if (!(pmtab
->p_ttyflags
& C_FLAG
)) {
551 (void) sprintf(pbuf
, "TTYPROMPT=%s", pmtab
->p_prompt
);
553 log("cannot expand service <%s> environment", argvp
[0]);
557 if (pmtab
->p_status
!= GETTY
) {
558 (void) sprintf(hbuf
, "HOME=%s", pmtab
->p_dir
);
560 log("cannot expand service <%s> environment", argvp
[0]);
564 debug("about to run config script");
566 if ((i
= doconfig(0, pmtab
->p_tag
, 0)) != 0) {
568 log("doconfig failed, system error");
571 log("doconfig failed on line %d of script %s",
578 if (setgid(pmtab
->p_gid
)) {
579 log("cannot set group id to %ld: %s", pmtab
->p_gid
,
584 if (setuid(pmtab
->p_uid
)) {
585 log("cannot set user id to %ld: %s", pmtab
->p_uid
,
590 if (chdir(pmtab
->p_dir
)) {
591 log("cannot chdir to %s: %s", pmtab
->p_dir
, strerror(errno
));
595 if (pmtab
->p_uid
!= ROOTUID
) {
596 /* change ownership and mode of device */
597 (void) fchown(0, pmtab
->p_uid
, Tty_gid
);
598 (void) fchmod(0, 0620);
602 if (pmtab
->p_status
!= GETTY
) {
604 sigact
.sa_handler
= SIG_DFL
;
605 (void) sigemptyset(&sigact
.sa_mask
);
606 (void) sigaction(SIGINT
, &sigact
, NULL
);
607 if (setrlimit(RLIMIT_NOFILE
, &Rlimit
) == -1) {
608 log("setrlimit failed: %s", strerror(errno
));
611 /* invoke the service */
612 log("Starting service (%s) on %s", argvp
[0], pmtab
->p_device
);
615 if (pmtab
->p_termtype
!= (char *)NULL
) {
616 (void) sprintf(tbuf
, "TERM=%s", pmtab
->p_termtype
);
618 log("cannot expand service <%s> environment", argvp
[0]);
622 /* restore signal handlers and mask */
623 (void) sigaction(SIGINT
, &Sigint
, NULL
);
624 (void) sigaction(SIGALRM
, &Sigalrm
, NULL
);
625 (void) sigaction(SIGPOLL
, &Sigpoll
, NULL
);
626 (void) sigaction(SIGQUIT
, &Sigquit
, NULL
);
627 (void) sigaction(SIGCLD
, &Sigcld
, NULL
);
628 (void) sigaction(SIGTERM
, &Sigterm
, NULL
);
630 (void) sigaction(SIGUSR1
, &Sigusr1
, NULL
);
631 (void) sigaction(SIGUSR2
, &Sigusr2
, NULL
);
633 (void) sigprocmask(SIG_SETMASK
, &Origmask
, NULL
);
634 (void) execve(argvp
[0], argvp
, environ
);
636 /* exec returns only on failure! */
637 log("tmchild: exec service failed: %s", strerror(errno
));
642 * check_hup(fd) - do a poll on fd to check if it is in hangup state
643 * - return 1 if hangup, otherwise return 0
651 struct pollfd pfd
[1];
654 pfd
[0].events
= POLLHUP
;
656 ret
= poll(pfd
, 1, 0);
660 log("check_hup: poll failed: %s", strerror(errno
));
664 if (pfd
[0].revents
& POLLHUP
) {
673 * sigpoll() - SIGPOLL handle for tmchild
674 * - when SIGPOLL is received by tmchild,
675 * the pipe between ttymon and tmchild is broken.
676 * Something must happen to ttymon.
682 debug("tmchild got SIGPOLL, exiting");