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 */
29 #include <stdio_ext.h>
36 #include <sys/types.h>
38 #include <sys/stropts.h>
39 #include <sys/resource.h>
40 #include <sys/termios.h>
51 static int Initialized
;
54 extern struct pollfd
*Pollp
;
55 static void initialize();
56 static void open_all();
57 static int set_poll();
58 static int check_spawnlimit();
59 static int mod_ttydefs();
64 extern int check_session();
65 extern void sigalarm();
66 extern void revokedevaccess(char *, uid_t
, gid_t
, mode_t
);
67 /* can't include libdevinfo.h */
68 extern int di_devperm_logout(const char *);
71 * ttymon - a port monitor under SAC
72 * - monitor ports, set terminal modes, baud rate
73 * and line discipline for the port
74 * - invoke service on port if connection request received
85 * - ttymon without args is invoked by SAC
86 * - ttymon -g is invoked by process that needs to
87 * have login service on the fly
91 main(int argc
, char *argv
[])
94 extern char *lastname();
97 * Only the superuser should execute this command.
102 /* remember original signal mask and dispositions */
103 (void) sigprocmask(SIG_SETMASK
, NULL
, &Origmask
);
104 (void) sigaction(SIGINT
, NULL
, &Sigint
);
105 (void) sigaction(SIGALRM
, NULL
, &Sigalrm
);
106 (void) sigaction(SIGPOLL
, NULL
, &Sigpoll
);
107 (void) sigaction(SIGQUIT
, NULL
, &Sigquit
);
108 (void) sigaction(SIGCLD
, NULL
, &Sigcld
);
109 (void) sigaction(SIGTERM
, NULL
, &Sigterm
);
111 (void) sigaction(SIGUSR1
, NULL
, &Sigusr1
);
112 (void) sigaction(SIGUSR2
, NULL
, &Sigusr2
);
116 * SIGQUIT needs to be ignored. Otherwise, hitting ^\ from
117 * console kills ttymon.
119 (void) signal(SIGQUIT
, SIG_IGN
);
121 if ((argc
> 1) || (strcmp(lastname(argv
[0]), "getty") == 0)) {
122 ttymon_express(argc
, argv
);
123 return (1); /*NOTREACHED*/
129 nfds
= set_poll(Pollp
);
132 do_poll(Pollp
, nfds
);
137 * READDB messages may arrive during poll or pause.
138 * So the flag needs to be checked again.
155 register struct passwd
*pwdp
;
156 register struct group
*gp
;
157 struct rlimit rlimit
;
158 extern struct rlimit Rlimit
;
159 extern uid_t Uucp_uid
;
160 extern gid_t Tty_gid
;
167 * get_environ() must be called first,
168 * otherwise we don't know where the log file is
176 log("PMTAG: %s", Tag
);
177 log("Starting state: %s",
178 (State
== PM_ENABLED
) ? "enabled" : "disabled");
182 debug("***** ttymon in initialize *****");
183 log("debug mode is \t on");
188 /* register to receive SIGPOLL when data comes to pmpipe */
189 if (ioctl(Pfd
, I_SETSIG
, S_INPUT
) < 0)
190 fatal("I_SETSIG on pmpipe failed: %s", strerror(errno
));
192 sacpoll(); /* this is needed because there may be data already */
194 Maxfiles
= (int)ulimit(4, 0L); /* get max number of open files */
196 fatal("ulimit(4,0L) failed: %s", strerror(errno
));
198 if (getrlimit(RLIMIT_NOFILE
, &Rlimit
) == -1)
199 fatal("getrlimit failed: %s", strerror(errno
));
201 rlimit
.rlim_cur
= rlimit
.rlim_max
= Rlimit
.rlim_max
;
202 if (setrlimit(RLIMIT_NOFILE
, &rlimit
) == -1)
203 fatal("setrlimit failed: %s", strerror(errno
));
205 (void) enable_extended_FILE_stdio(-1, -1);
207 Maxfiles
= rlimit
.rlim_cur
;
208 Maxfds
= Maxfiles
- FILE_RESERVED
;
210 log("max open files = %d", Maxfiles
);
211 log("max ports ttymon can monitor = %d", Maxfds
);
217 * - we allocate 10 extra pollfd so that
218 * we do not have to re-malloc when there is
219 * minor fluctuation in Nentries
221 Npollfd
= Nentries
+ 10;
222 if (Npollfd
> Maxfds
)
224 if ((Pollp
= (struct pollfd
*)
225 malloc((unsigned)(Npollfd
* sizeof (struct pollfd
))))
226 == (struct pollfd
*)NULL
)
227 fatal("malloc for Pollp failed");
229 (void) mod_ttydefs(); /* just to initialize Mtime */
230 if (check_version(TTYDEFS_VERS
, TTYDEFS
) != 0)
231 fatal("check /etc/ttydefs version failed");
233 read_ttydefs(NULL
, FALSE
);
235 /* initialize global variables, Uucp_uid & Tty_gid */
236 if ((pwdp
= getpwnam(UUCP
)) != NULL
)
237 Uucp_uid
= pwdp
->pw_uid
;
238 if ((gp
= getgrnam(TTY
)) == NULL
)
239 log("no group entry for <tty>, default is used");
241 Tty_gid
= gp
->gr_gid
;
245 debug("Uucp_uid = %u, Tty_gid = %u", Uucp_uid
, Tty_gid
);
248 log("Initialization Completed");
250 /* open the devices ttymon monitors */
254 for (tp
= PMtab
; tp
; tp
= tp
->p_next
) {
255 if ((tp
->p_status
> 0) && (tp
->p_fd
== 0) &&
256 (tp
->p_pid
== 0) && !(tp
->p_ttyflags
& I_FLAG
) &&
257 (!((State
== PM_DISABLED
) &&
258 ((tp
->p_dmsg
== NULL
)||(*(tp
->p_dmsg
) == '\0'))))) {
268 static void free_defs();
271 * open_all - open devices in pmtab if the entry is
272 * - valid, fd = 0, and pid = 0
283 debug("in open_all");
285 check_modtime
= TRUE
;
287 for (tp
= PMtab
; tp
; tp
= tp
->p_next
) {
288 if ((tp
->p_status
> 0) && (tp
->p_fd
== 0) &&
290 !(tp
->p_ttyflags
& I_FLAG
) && (!((State
== PM_DISABLED
) &&
291 ((tp
->p_dmsg
== NULL
)||(*(tp
->p_dmsg
) == '\0'))))) {
293 * if we have not check modification time and
294 * /etc/ttydefs was modified, need to re-read it
296 if (check_modtime
&& mod_ttydefs()) {
297 check_modtime
= FALSE
;
298 (void) sigprocmask(SIG_SETMASK
, NULL
, &cset
);
300 (void) sigaddset(&tset
, SIGCLD
);
301 (void) sigprocmask(SIG_SETMASK
, &tset
, NULL
);
304 debug("/etc/ttydefs is modified, re-read it");
306 read_ttydefs(NULL
, FALSE
);
307 (void) sigprocmask(SIG_SETMASK
, &cset
, NULL
);
312 } else if (((tp
->p_status
== LOCKED
) ||
313 (tp
->p_status
== SESSION
) ||
314 (tp
->p_status
== UNACCESS
)) &&
316 (!((State
== PM_DISABLED
) &&
317 ((tp
->p_dmsg
== NULL
)||(*(tp
->p_dmsg
) == '\0'))))) {
318 if (check_modtime
&& mod_ttydefs()) {
319 check_modtime
= FALSE
;
320 (void) sigprocmask(SIG_SETMASK
, NULL
, &cset
);
322 (void) sigaddset(&tset
, SIGCLD
);
323 (void) sigprocmask(SIG_SETMASK
, &tset
, NULL
);
326 debug("/etc/ttydefs is modified, re-read it");
328 read_ttydefs(NULL
, FALSE
);
329 (void) sigprocmask(SIG_SETMASK
, &cset
, NULL
);
331 tp
->p_status
= VALID
;
347 debug("in set_softcar");
350 * If soft carrier is not set one way or
351 * the other, leave it alone.
353 if (*pmptr
->p_softcar
== '\0')
356 if (*pmptr
->p_softcar
== 'y')
359 if ((fd
= open(pmptr
->p_device
, O_RDONLY
|O_NONBLOCK
|O_NOCTTY
)) < 0) {
360 log("open (%s) failed: %s", pmptr
->p_device
, strerror(errno
));
364 if (ioctl(fd
, TIOCSSOFTCAR
, &val
) < 0)
365 log("set soft-carrier (%s) failed: %s", pmptr
->p_device
,
373 * open_device(pmptr) - open the device
374 * - check device lock
375 * - change owner of device
376 * - push line disciplines
385 struct sigaction sigact
;
388 debug("in open_device");
391 if (pmptr
->p_status
== GETTY
) {
392 revokedevaccess(pmptr
->p_device
, 0, 0, 0);
394 if ((fd
= open(pmptr
->p_device
, O_RDWR
)) == -1)
395 fatal("open (%s) failed: %s", pmptr
->p_device
,
399 if (check_spawnlimit(pmptr
) == -1) {
400 pmptr
->p_status
= NOTVALID
;
401 log("service <%s> is respawning too rapidly",
405 if (pmptr
->p_fd
> 0) { /* file already open */
408 } else if ((fd
= open(pmptr
->p_device
, O_RDWR
|O_NONBLOCK
))
410 log("open (%s) failed: %s", pmptr
->p_device
,
412 if ((errno
== ENODEV
) || (errno
== EBUSY
)) {
413 pmptr
->p_status
= UNACCESS
;
417 sigact
.sa_handler
= sigalarm
;
418 (void) sigemptyset(&sigact
.sa_mask
);
419 (void) sigaction(SIGALRM
, &sigact
, NULL
);
420 (void) alarm(ALARMTIME
);
426 /* set close-on-exec flag */
427 if (fcntl(fd
, F_SETFD
, 1) == -1)
428 fatal("F_SETFD fcntl failed: %s", strerror(errno
));
430 if (tm_checklock(fd
) != 0) {
431 pmptr
->p_status
= LOCKED
;
436 sigact
.sa_handler
= sigalarm
;
437 (void) sigemptyset(&sigact
.sa_mask
);
438 (void) sigaction(SIGALRM
, &sigact
, NULL
);
439 (void) alarm(ALARMTIME
);
443 if (check_session(fd
) != 0) {
444 if ((Initialized
) && (pmptr
->p_inservice
!= SESSION
)) {
445 log("Warning -- active session exists on <%s>",
449 * this may happen if a service is running
450 * and ttymon dies and is restarted,
451 * or another process is running on the
454 pmptr
->p_status
= SESSION
;
455 pmptr
->p_inservice
= 0;
460 sigact
.sa_handler
= sigalarm
;
461 (void) sigemptyset(&sigact
.sa_mask
);
462 (void) sigaction(SIGALRM
, &sigact
,
464 (void) alarm(ALARMTIME
);
469 pmptr
->p_inservice
= 0;
472 if (pmptr
->p_ttyflags
& H_FLAG
) {
474 (void) hang_up_line(fd
);
476 * After hang_up_line, the stream is in STRHUP state.
477 * We need to do another open to reinitialize streams
478 * then we can close one fd
480 if ((tmpfd
= open(pmptr
->p_device
, O_RDWR
|O_NONBLOCK
)) == -1) {
481 log("open (%s) failed: %s", pmptr
->p_device
,
491 debug("open_device (%s), fd = %d", pmptr
->p_device
, fd
);
494 /* Change ownership of the tty line to root/uucp and */
495 /* set protections to only allow root/uucp to read the line. */
497 if (pmptr
->p_ttyflags
& (B_FLAG
|C_FLAG
))
498 (void) fchown(fd
, Uucp_uid
, Tty_gid
);
500 (void) fchown(fd
, ROOTUID
, Tty_gid
);
501 (void) fchmod(fd
, 0620);
503 if ((pmptr
->p_modules
!= NULL
)&&(*(pmptr
->p_modules
) != '\0')) {
504 if (push_linedisc(fd
, pmptr
->p_modules
, pmptr
->p_device
)
512 if (initial_termio(fd
, pmptr
) == -1) {
518 di_devperm_logout((const char *)pmptr
->p_device
);
523 * set_poll(fdp) - put all fd's in a pollfd array
524 * - set poll event to POLLIN and POLLMSG
525 * - return number of fd to be polled
535 for (tp
= PMtab
; tp
; tp
= tp
->p_next
) {
538 fdp
->events
= POLLIN
;
547 * check_spawnlimit - return 0 if spawnlimit is not reached
548 * - otherwise return -1
551 check_spawnlimit(pmptr
)
557 if (pmptr
->p_time
== 0L)
559 if (pmptr
->p_respawn
>= SPAWN_LIMIT
) {
560 if ((now
- pmptr
->p_time
) < SPAWN_INTERVAL
) {
562 pmptr
->p_respawn
= 0;
566 pmptr
->p_respawn
= 0;
573 * mod_ttydefs - to check if /etc/ttydefs has been modified
574 * - return TRUE if file modified
575 * - otherwise, return FALSE
582 if (stat(TTYDEFS
, &statbuf
) == -1) {
583 /* if stat failed, don't bother reread ttydefs */
586 if ((long)statbuf
.st_mtime
!= Mtime
) {
587 Mtime
= (long)statbuf
.st_mtime
;
594 * free_defs - free the Gdef table
602 for (i
= 0; i
< Ndefs
; i
++, tp
++) {
616 * struct Gdef *get_speed(ttylabel)
617 * - search "/etc/ttydefs" for speed and term. specification
618 * using "ttylabel". If "ttylabel" is NULL, default
620 * arg: ttylabel - label/id of speed settings.
624 get_speed(char *ttylabel
)
626 register struct Gdef
*sp
;
627 extern struct Gdef DEFAULT
;
629 if ((ttylabel
!= NULL
) && (*ttylabel
!= '\0')) {
630 if ((sp
= find_def(ttylabel
)) == NULL
) {
631 log("unable to find <%s> in \"%s\"", ttylabel
, TTYDEFS
);
632 sp
= &DEFAULT
; /* use default */
634 } else sp
= &DEFAULT
; /* use default */
639 * setup_PCpipe() - setup the pipe between Parent and Children
640 * - the pipe is used for a tmchild to send its
641 * pid to inform ttymon that it is about to
643 * - the pipe also serves as a mean for tmchild
644 * to detect failure of ttymon
651 if (pipe(PCpipe
) == -1)
652 fatal("pipe() failed: %s", strerror(errno
));
654 /* set close-on-exec flag */
655 if (fcntl(PCpipe
[0], F_SETFD
, 1) == -1)
656 fatal("F_SETFD fcntl failed: %s", strerror(errno
));
658 if (fcntl(PCpipe
[1], F_SETFD
, 1) == -1)
659 fatal("F_SETFD fcntl failed: %s", strerror(errno
));
661 /* set O_NONBLOCK flag */
662 if (fcntl(PCpipe
[0], F_GETFL
, flag
) == -1)
663 fatal("F_GETFL failed: %s", strerror(errno
));
666 if (fcntl(PCpipe
[0], F_SETFL
, flag
) == -1)
667 fatal("F_SETFL failed: %s", strerror(errno
));
669 /* set message discard mode */
670 if (ioctl(PCpipe
[0], I_SRDOPT
, RMSGD
) == -1)
671 fatal("I_SRDOPT RMSGD failed: %s", strerror(errno
));
673 /* register to receive SIGPOLL when data come */
674 if (ioctl(PCpipe
[0], I_SETSIG
, S_INPUT
) == -1)
675 fatal("I_SETSIG S_INPUT failed: %s", strerror(errno
));
678 log("PCpipe[0]\t = %d", PCpipe
[0]);
679 log("PCpipe[1]\t = %d", PCpipe
[1]);