]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/agetty.c
1 /* agetty.c - another getty program for Linux. By W. Z. Venema 1989
2 Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
3 This program is freely distributable. The entire man-page used to
4 be here. Now read the real man-page agetty.8 instead.
6 -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
13 #include <sys/ioctl.h>
17 #include <sys/types.h>
28 #include "pathnames.h"
29 #include <sys/param.h>
33 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
37 extern void closelog();
41 * Some heuristics to find out what environment we are in: if it is not
42 * System V, assume it is SunOS 4.
45 #ifdef LOGIN_PROCESS /* defined in System V utmp.h */
46 #define SYSV_STYLE /* select System V style getty */
50 * Things you may want to modify.
52 * If ISSUE is not defined, agetty will never display the contents of the
53 * /etc/issue file. You will not want to spit out large "issue" files at the
54 * wrong baud rate. Relevant for System V only.
56 * You may disagree with the default line-editing etc. characters defined
57 * below. Note, however, that DEL cannot be used for interrupt generation
58 * and for line editing at the same time.
62 #define ISSUE "/etc/issue" /* displayed before the login prompt */
63 #include <sys/utsname.h>
67 #define LOGIN " login: " /* login prompt */
69 /* Some shorthands for control characters. */
71 #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
72 #define CR CTL('M') /* carriage return */
73 #define NL CTL('J') /* line feed */
74 #define BS CTL('H') /* back space */
75 #define DEL CTL('?') /* delete */
77 /* Defaults for line-editing etc. characters; you may want to change this. */
79 #define DEF_ERASE DEL /* default erase character */
80 #define DEF_INTR CTL('C') /* default interrupt character */
81 #define DEF_QUIT CTL('\\') /* default quit char */
82 #define DEF_KILL CTL('U') /* default kill char */
83 #define DEF_EOF CTL('D') /* default EOF char */
85 #define DEF_SWITCH 0 /* default switch char */
88 * SunOS 4.1.1 termio is broken. We must use the termios stuff instead,
89 * because the termio -> termios translation does not clear the termios
90 * CIBAUD bits. Therefore, the tty driver would sometimes report that input
91 * baud rate != output baud rate. I did not notice that problem with SunOS
92 * 4.1. We will use termios where available, and termio otherwise.
95 /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set
96 properly, but all is well if we use termios?! */
102 #define termio termios
103 #define TCGETA TCGETS
104 #define TCSETA TCSETS
105 #define TCSETAW TCSETSW
109 * This program tries to not use the standard-i/o library. This keeps the
110 * executable small on systems that do not have shared libraries (System V
118 * When multiple baud rates are specified on the command line, the first one
119 * we will try is the first one specified.
122 #define FIRST_SPEED 0
124 /* Storage for command-line options. */
126 #define MAX_SPEED 10 /* max. nr. of baud rates */
129 int flags
; /* toggle switches, see below */
130 int timeout
; /* time-out period */
131 char *login
; /* login program */
132 char *tty
; /* name of tty */
133 char *initstring
; /* modem init string */
134 char *issue
; /* alternative issue file */
135 int numspeed
; /* number of baud rates to try */
136 int speeds
[MAX_SPEED
]; /* baud rates to be tried */
139 #define F_PARSE (1<<0) /* process modem status messages */
140 #define F_ISSUE (1<<1) /* display /etc/issue */
141 #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
142 #define F_LOCAL (1<<3) /* force local */
143 #define F_INITSTRING (1<<4) /* initstring is set */
144 #define F_WAITCRLF (1<<5) /* wait for CR or LF */
145 #define F_CUSTISSUE (1<<6) /* give alternative issue file */
146 #define F_NOPROMPT (1<<7) /* don't ask for login name! */
148 /* Storage for things detected while the login name was read. */
151 int erase
; /* erase character */
152 int kill
; /* kill character */
153 int eol
; /* end-of-line character */
154 int parity
; /* what parity did we see */
155 int capslock
; /* upper case without lower case */
158 /* Initial values for the above. */
160 struct chardata init_chardata
= {
161 DEF_ERASE
, /* default erase character */
162 DEF_KILL
, /* default kill character */
163 13, /* default eol char */
164 0, /* space parity */
173 static struct Speedtab speedtab
[] = {
212 void parse_args
P_((int argc
, char **argv
, struct options
*op
));
213 void parse_speeds
P_((struct options
*op
, char *arg
));
214 void update_utmp
P_((char *line
));
215 void open_tty
P_((char *tty
, struct termio
*tp
, int local
));
216 void termio_init
P_((struct termio
*tp
, int speed
, int local
));
217 void auto_baud
P_((struct termio
*tp
));
218 void do_prompt
P_((struct options
*op
, struct termio
*tp
));
219 void next_speed
P_((struct termio
*tp
, struct options
*op
));
220 char *get_logname
P_((struct options
*op
, struct chardata
*cp
, struct termio
*tp
));
221 void termio_final
P_((struct options
*op
, struct termio
*tp
, struct chardata
*cp
));
222 int caps_lock
P_((char *s
));
223 int bcode
P_((char *s
));
224 void usage
P_((void));
225 void error
P_((int va_alist
));
228 /* The following is used for understandable diagnostics. */
234 #define debug(s) fprintf(dbf,s); fflush(dbf)
237 #define debug(s) /* nothing */
245 char *logname
= NULL
; /* login name, given to /bin/login */
246 struct chardata chardata
; /* set by get_logname() */
247 struct termio termio
; /* terminal mode bits */
248 static struct options options
= {
249 F_ISSUE
, /* show /etc/issue (SYSV_STYLE) */
251 _PATH_LOGIN
, /* default login program */
252 "tty1", /* default tty line */
253 "", /* modem init string */
254 ISSUE
, /* default issue file */
255 0, /* no baud rates known yet */
258 /* The BSD-style init command passes us a useless process name. */
267 dbf
= fopen("/dev/ttyp0", "w");
271 for(i
= 1; i
< argc
; i
++) {
277 /* Parse command-line arguments. */
279 parse_args(argc
, argv
, &options
);
285 /* Update the utmp file. */
288 update_utmp(options
.tty
);
291 debug("calling open_tty\n");
292 /* Open the tty as standard { input, output, error }. */
293 open_tty(options
.tty
, &termio
, options
.flags
& F_LOCAL
);
300 (void) ioctl(0, TIOCSPGRP
, &iv
);
303 /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
304 debug("calling termio_init\n");
305 termio_init(&termio
, options
.speeds
[FIRST_SPEED
], options
.flags
& F_LOCAL
);
307 /* write the modem init string and DON'T flush the buffers */
308 if (options
.flags
& F_INITSTRING
) {
309 debug("writing init string\n");
310 write(1, options
.initstring
, strlen(options
.initstring
));
313 if (!(options
.flags
& F_LOCAL
)) {
314 /* go to blocking write mode unless -L is specified */
315 fcntl(1, F_SETFL
, fcntl(1, F_GETFL
, 0) & ~O_NONBLOCK
);
318 /* Optionally detect the baud rate from the modem status message. */
319 debug("before autobaud\n");
320 if (options
.flags
& F_PARSE
)
323 /* Set the optional timer. */
325 (void) alarm((unsigned) options
.timeout
);
327 /* optionally wait for CR or LF before writing /etc/issue */
328 if (options
.flags
& F_WAITCRLF
) {
331 debug("waiting for cr-lf\n");
332 while(read(0, &ch
, 1) == 1) {
333 ch
&= 0x7f; /* strip "parity bit" */
335 fprintf(dbf
, "read %c\n", ch
);
337 if (ch
== '\n' || ch
== '\r') break;
341 chardata
= init_chardata
;
342 if (!(options
.flags
& F_NOPROMPT
)) {
343 /* Read the login name. */
344 debug("reading login name\n");
345 while ((logname
= get_logname(&options
, &chardata
, &termio
)) == 0)
346 next_speed(&termio
, &options
);
354 /* Finalize the termio settings. */
356 termio_final(&options
, &termio
, &chardata
);
358 /* Now the newline character should be properly written. */
360 (void) write(1, "\n", 1);
362 /* Let the login program take care of password validation. */
364 (void) execl(options
.login
, options
.login
, "--", logname
, (char *) 0);
365 error("%s: can't exec %s: %m", options
.tty
, options
.login
);
366 exit(0); /* quiet GCC */
369 /* parse-args - parse command-line arguments */
372 parse_args(argc
, argv
, op
)
377 extern char *optarg
; /* getopt */
378 extern int optind
; /* getopt */
381 while (isascii(c
= getopt(argc
, argv
, "I:Lf:hil:mt:wn"))) {
384 if (!(op
->initstring
= malloc(strlen(optarg
)))) {
385 error("can't malloc initstring");
392 /* copy optarg into op->initstring decoding \ddd
393 octal codes into chars */
397 if (*p
== '\\') { /* know \\ means \ */
402 } else { /* handle \000 - \177 */
404 for (i
= 1; i
<= 3; i
++) {
405 if (*p
>= '0' && *p
<= '7') {
420 op
->flags
|= F_INITSTRING
;
423 case 'L': /* force local */
424 op
->flags
|= F_LOCAL
;
426 case 'f': /* custom issue file */
427 op
->flags
|= F_CUSTISSUE
;
430 case 'h': /* enable h/w flow control */
431 op
->flags
|= F_RTSCTS
;
433 case 'i': /* do not show /etc/issue */
434 op
->flags
&= ~F_ISSUE
;
437 op
->login
= optarg
; /* non-default login program */
439 case 'm': /* parse modem status message */
440 op
->flags
|= F_PARSE
;
443 op
->flags
|= F_NOPROMPT
;
445 case 't': /* time out */
446 if ((op
->timeout
= atoi(optarg
)) <= 0)
447 error("bad timeout value: %s", optarg
);
450 op
->flags
|= F_WAITCRLF
;
456 debug("after getopt loop\n");
457 if (argc
< optind
+ 2) /* check parameter count */
460 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
461 if('0' <= argv
[optind
][0] && argv
[optind
][0] <= '9') {
462 /* a number first, assume it's a speed (BSD style) */
463 parse_speeds(op
, argv
[optind
++]); /* baud rate(s) */
464 op
->tty
= argv
[optind
]; /* tty name */
466 op
->tty
= argv
[optind
++]; /* tty name */
467 parse_speeds(op
, argv
[optind
]); /* baud rate(s) */
471 if (argc
> optind
&& argv
[optind
])
472 setenv ("TERM", argv
[optind
], 1);
474 debug("exiting parseargs\n");
477 /* parse_speeds - parse alternate baud rates */
480 parse_speeds(op
, arg
)
487 debug("entered parse_speeds\n");
488 for (cp
= strtok(arg
, ","); cp
!= 0; cp
= strtok((char *) 0, ",")) {
489 if ((op
->speeds
[op
->numspeed
++] = bcode(cp
)) <= 0)
490 error("bad speed: %s", cp
);
491 if (op
->numspeed
> MAX_SPEED
)
492 error("too many alternate speeds");
494 debug("exiting parsespeeds\n");
499 /* update_utmp - update our utmp entry */
507 int mypid
= getpid();
513 * The utmp file holds miscellaneous information about things started by
514 * /sbin/init and other system-related events. Our purpose is to update
515 * the utmp entry for the current process, in particular the process type
516 * and the tty line we are listening to. Return successfully only if the
517 * utmp file can be opened for update, and if we are able to find our
518 * entry in the utmp file.
522 utmpname(_PATH_UTMP
);
524 while ((utp
= getutent())
525 && !(utp
->ut_type
== INIT_PROCESS
526 && utp
->ut_pid
== mypid
)) /* nothing */;
529 memcpy(&ut
, utp
, sizeof(ut
));
531 /* some inits don't initialize utmp... */
532 memset(&ut
, 0, sizeof(ut
));
533 strncpy(ut
.ut_id
, line
+ 3, sizeof(ut
.ut_id
));
537 strncpy(ut
.ut_user
, "LOGIN", sizeof(ut
.ut_user
));
538 strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
541 ut
.ut_type
= LOGIN_PROCESS
;
548 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
549 updwtmp(_PATH_WTMP
, &ut
);
553 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
555 if ((ut_fd
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
556 write(ut_fd
, &ut
, sizeof(ut
));
564 #else /* not __linux__ */
565 if ((ut_fd
= open(UTMP_FILE
, 2)) < 0) {
566 error("%s: open for update: %m", UTMP_FILE
);
568 long ut_size
= sizeof(ut
); /* avoid nonsense */
570 while (read(ut_fd
, (char *) &ut
, sizeof(ut
)) == sizeof(ut
)) {
571 if (ut
.ut_type
== INIT_PROCESS
&& ut
.ut_pid
== mypid
) {
572 ut
.ut_type
= LOGIN_PROCESS
;
573 ut
.ut_time
= time((long *) 0);
574 (void) strncpy(ut
.ut_name
, "LOGIN", sizeof(ut
.ut_name
));
575 (void) strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
576 (void) lseek(ut_fd
, -ut_size
, 1);
577 (void) write(ut_fd
, (char *) &ut
, sizeof(ut
));
582 error("%s: no utmp entry", line
);
584 #endif /* __linux__ */
589 /* open_tty - set up tty as standard { input, output, error } */
591 open_tty(tty
, tp
, local
)
596 /* Get rid of the present standard { output, error} if any. */
600 errno
= 0; /* ignore above errors */
602 /* Set up new standard input, unless we are given an already opened port. */
604 if (strcmp(tty
, "-")) {
607 /* Sanity checks... */
610 error("/dev: chdir() failed: %m");
611 if (stat(tty
, &st
) < 0)
612 error("/dev/%s: %m", tty
);
613 if ((st
.st_mode
& S_IFMT
) != S_IFCHR
)
614 error("/dev/%s: not a character device", tty
);
616 /* Open the tty as standard input. */
619 errno
= 0; /* ignore close(2) errors */
622 if (open(tty
, O_RDWR
|O_NONBLOCK
, 0) != 0)
623 error("/dev/%s: cannot open as standard input: %m", tty
);
628 * Standard input should already be connected to an open port. Make
629 * sure it is open for read/write.
632 if ((fcntl(0, F_GETFL
, 0) & O_RDWR
) != O_RDWR
)
633 error("%s: not open for read/write", tty
);
636 /* Set up standard output and standard error file descriptors. */
638 if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */
639 error("%s: dup problem: %m", tty
); /* we have a problem */
642 * The following ioctl will fail if stdin is not a tty, but also when
643 * there is noise on the modem control lines. In the latter case, the
644 * common course of action is (1) fix your cables (2) give the modem more
645 * time to properly reset after hanging up. SunOS users can achieve (2)
646 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
647 * 5 seconds seems to be a good value.
650 if (ioctl(0, TCGETA
, tp
) < 0)
651 error("%s: ioctl: %m", tty
);
654 * It seems to be a terminal. Set proper protections and ownership. Mode
655 * 0622 is suitable for SYSV <4 because /bin/login does not change
656 * protections. SunOS 4 login will change the protections to 0620 (write
657 * access for group tty) after the login has succeeded.
660 (void) chown(tty
, 0, 0); /* root, sys */
661 (void) chmod(tty
, 0622); /* crw--w--w- */
662 errno
= 0; /* ignore above errors */
665 /* termio_init - initialize termio settings */
671 termio_init(tp
, speed
, local
)
678 * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
679 * Special characters are set after we have read the login name; all
680 * reads will be done in raw mode anyway. Errors will be dealt with
684 /* flush input and output queues, important for modems! */
685 (void) ioctl(0, TCFLSH
, TCIOFLUSH
);
688 tp
->c_cflag
= CS8
| HUPCL
| CREAD
| speed
;
690 tp
->c_cflag
|= CLOCAL
;
693 tp
->c_iflag
= tp
->c_lflag
= tp
->c_oflag
= tp
->c_line
= 0;
696 (void) ioctl(0, TCSETA
, tp
);
698 /* go to blocking input even in local mode */
699 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) & ~O_NONBLOCK
);
701 debug("term_io 2\n");
704 /* auto_baud - extract baud rate from modem status message */
717 * This works only if the modem produces its status code AFTER raising
718 * the DCD line, and if the computer is fast enough to set the proper
719 * baud rate before the message has gone by. We expect a message of the
722 * <junk><number><junk>
724 * The number is interpreted as the baud rate of the incoming call. If the
725 * modem does not tell us the baud rate within one second, we will keep
726 * using the current baud rate. It is advisable to enable BREAK
727 * processing (comma-separated list of baud rates) if the processing of
728 * modem status messages is enabled.
732 * Use 7-bit characters, don't block if input queue is empty. Errors will
733 * be dealt with lateron.
737 tp
->c_iflag
|= ISTRIP
; /* enable 8th-bit stripping */
738 vmin
= tp
->c_cc
[VMIN
];
739 tp
->c_cc
[VMIN
] = 0; /* don't block if queue empty */
740 (void) ioctl(0, TCSETA
, tp
);
743 * Wait for a while, then read everything the modem has said so far and
744 * try to extract the speed of the dial-in call.
748 if ((nread
= read(0, buf
, sizeof(buf
) - 1)) > 0) {
750 for (bp
= buf
; bp
< buf
+ nread
; bp
++) {
751 if (isascii(*bp
) && isdigit(*bp
)) {
752 if ((speed
= bcode(bp
))) {
753 tp
->c_cflag
&= ~CBAUD
;
754 tp
->c_cflag
|= speed
;
760 /* Restore terminal settings. Errors will be dealt with lateron. */
763 tp
->c_cc
[VMIN
] = vmin
;
764 (void) ioctl(0, TCSETA
, tp
);
767 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
782 (void) write(1, "\r\n", 2); /* start a new line */
783 #ifdef ISSUE /* optional: show /etc/issue */
784 if ((op
->flags
& F_ISSUE
) && (fd
= fopen(op
->issue
, "r"))) {
785 oflag
= tp
->c_oflag
; /* save current setting */
786 tp
->c_oflag
|= (ONLCR
| OPOST
); /* map NL in output to CR-NL */
787 (void) ioctl(0, TCSETAW
, tp
);
790 while ((c
= getc(fd
)) != EOF
)
799 (void) printf ("%s", uts
.sysname
);
803 (void) printf ("%s", uts
.nodename
);
807 (void) printf ("%s", uts
.release
);
811 (void) printf ("%s", uts
.version
);
815 (void) printf ("%s", uts
.machine
);
820 char domainname
[256];
822 getdomainname(domainname
, sizeof(domainname
));
823 domainname
[sizeof(domainname
)-1] = '\0';
824 printf ("%s", domainname
);
831 char *weekday
[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
833 char *month
[] = { "Jan", "Feb", "Mar", "Apr", "May",
834 "Jun", "Jul", "Aug", "Sep", "Oct",
840 tm
= localtime(&now
);
843 (void) printf ("%s %s %d %d",
844 weekday
[tm
->tm_wday
], month
[tm
->tm_mon
],
846 tm
->tm_year
< 70 ? tm
->tm_year
+ 2000 :
849 (void) printf ("%02d:%02d:%02d",
850 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
856 (void) printf ("%s", op
->tty
);
863 for (i
= 0; speedtab
[i
].speed
; i
++) {
864 if (speedtab
[i
].code
== (tp
->c_cflag
& CBAUD
)) {
865 printf("%ld", speedtab
[i
].speed
);
877 while ((ut
= getutent()))
878 if (ut
->ut_type
== USER_PROCESS
)
881 printf ("%d", users
);
883 printf (" user%s", users
== 1 ? "" : "s");
895 tp
->c_oflag
= oflag
; /* restore settings */
896 (void) ioctl(0, TCSETAW
, tp
); /* wait till output is gone */
902 char hn
[MAXHOSTNAMELEN
+1];
904 (void) gethostname(hn
, MAXHOSTNAMELEN
);
905 write(1, hn
, strlen(hn
));
908 (void) write(1, LOGIN
, sizeof(LOGIN
) - 1); /* always show login prompt */
911 /* next_speed - select next baud rate */
917 static int baud_index
= FIRST_SPEED
;/* current speed index */
919 baud_index
= (baud_index
+ 1) % op
->numspeed
;
920 tp
->c_cflag
&= ~CBAUD
;
921 tp
->c_cflag
|= op
->speeds
[baud_index
];
922 (void) ioctl(0, TCSETA
, tp
);
925 /* get_logname - get user name, establish parity, speed, erase, kill, eol */
927 char *get_logname(op
, cp
, tp
)
932 static char logname
[BUFSIZ
];
934 char c
; /* input character, full eight bits */
935 char ascval
; /* low 7 bits of input character */
936 int bits
; /* # of "1" bits per character */
937 int mask
; /* mask with 1 bit up */
938 static char *erase
[] = { /* backspace-space-backspace */
939 "\010\040\010", /* space parity */
940 "\010\040\010", /* odd parity */
941 "\210\240\210", /* even parity */
942 "\210\240\210", /* no parity */
945 /* Initialize kill, erase, parity etc. (also after switching speeds). */
949 /* Flush pending input (esp. after parsing or switching the baud rate). */
952 (void) ioctl(0, TCFLSH
, TCIFLUSH
);
954 /* Prompt for and read a login name. */
956 for (*logname
= 0; *logname
== 0; /* void */ ) {
958 /* Write issue file and prompt, with "parity" bit == 0. */
962 /* Read name, watch for break, parity, erase, kill, end-of-line. */
964 for (bp
= logname
, cp
->eol
= 0; cp
->eol
== 0; /* void */ ) {
966 /* Do not report trivial EINTR/EIO errors. */
968 if (read(0, &c
, 1) < 1) {
969 if (errno
== EINTR
|| errno
== EIO
)
971 error("%s: read: %m", op
->tty
);
973 /* Do BREAK handling elsewhere. */
975 if ((c
== 0) && op
->numspeed
> 1)
978 /* Do parity bit handling. */
980 if (c
!= (ascval
= (c
& 0177))) { /* "parity" bit on ? */
981 for (bits
= 1, mask
= 1; mask
& 0177; mask
<<= 1)
983 bits
++; /* count "1" bits */
984 cp
->parity
|= ((bits
& 1) ? 1 : 2);
986 /* Do erase, kill and end-of-line processing. */
991 *bp
= 0; /* terminate logname */
992 cp
->eol
= ascval
; /* set end-of-line char */
997 cp
->erase
= ascval
; /* set erase character */
999 (void) write(1, erase
[cp
->parity
], 3);
1005 cp
->kill
= ascval
; /* set kill character */
1006 while (bp
> logname
) {
1007 (void) write(1, erase
[cp
->parity
], 3);
1014 if (!isascii(ascval
) || !isprint(ascval
)) {
1015 /* ignore garbage characters */ ;
1016 } else if (bp
- logname
>= sizeof(logname
) - 1) {
1017 error("%s: input overrun", op
->tty
);
1019 (void) write(1, &c
, 1); /* echo the character */
1020 *bp
++ = ascval
; /* and store it */
1026 /* Handle names with upper case and no lower case. */
1028 if ((cp
->capslock
= caps_lock(logname
))) {
1029 for (bp
= logname
; *bp
; bp
++)
1031 *bp
= tolower(*bp
); /* map name to lower case */
1036 /* termio_final - set the final tty mode bits */
1038 termio_final(op
, tp
, cp
)
1041 struct chardata
*cp
;
1043 /* General terminal-independent stuff. */
1045 tp
->c_iflag
|= IXON
| IXOFF
; /* 2-way flow control */
1046 tp
->c_lflag
|= ICANON
| ISIG
| ECHO
| ECHOE
| ECHOK
| ECHOKE
;
1047 /* no longer| ECHOCTL | ECHOPRT*/
1048 tp
->c_oflag
|= OPOST
;
1049 /* tp->c_cflag = 0; */
1050 tp
->c_cc
[VINTR
] = DEF_INTR
; /* default interrupt */
1051 tp
->c_cc
[VQUIT
] = DEF_QUIT
; /* default quit */
1052 tp
->c_cc
[VEOF
] = DEF_EOF
; /* default EOF character */
1053 tp
->c_cc
[VEOL
] = DEF_EOL
;
1055 tp
->c_cc
[VSWTC
] = DEF_SWITCH
; /* default switch character */
1057 tp
->c_cc
[VSWTCH
] = DEF_SWITCH
; /* default switch character */
1060 /* Account for special characters seen in input. */
1062 if (cp
->eol
== CR
) {
1063 tp
->c_iflag
|= ICRNL
; /* map CR in input to NL */
1064 tp
->c_oflag
|= ONLCR
; /* map NL in output to CR-NL */
1066 tp
->c_cc
[VERASE
] = cp
->erase
; /* set erase character */
1067 tp
->c_cc
[VKILL
] = cp
->kill
; /* set kill character */
1069 /* Account for the presence or absence of parity bits in input. */
1071 switch (cp
->parity
) {
1072 case 0: /* space (always 0) parity */
1074 case 1: /* odd parity */
1075 tp
->c_cflag
|= PARODD
;
1077 case 2: /* even parity */
1078 tp
->c_cflag
|= PARENB
;
1079 tp
->c_iflag
|= INPCK
| ISTRIP
;
1081 case (1 | 2): /* no parity bit */
1082 tp
->c_cflag
&= ~CSIZE
;
1086 /* Account for upper case without lower case. */
1089 tp
->c_iflag
|= IUCLC
;
1090 tp
->c_lflag
|= XCASE
;
1091 tp
->c_oflag
|= OLCUC
;
1093 /* Optionally enable hardware flow control */
1096 if (op
->flags
& F_RTSCTS
)
1097 tp
->c_cflag
|= CRTSCTS
;
1100 /* Finally, make the new settings effective */
1102 if (ioctl(0, TCSETA
, tp
) < 0)
1103 error("%s: ioctl: TCSETA: %m", op
->tty
);
1106 /* caps_lock - string contains upper case without lower case */
1113 for (capslock
= 0; *s
; s
++) {
1117 capslock
= isupper(*s
);
1122 /* bcode - convert speed string to speed code; return 0 on failure */
1127 struct Speedtab
*sp
;
1128 long speed
= atol(s
);
1130 for (sp
= speedtab
; sp
->speed
; sp
++)
1131 if (sp
->speed
== speed
)
1136 /* usage - explain */
1142 "[-hiLmw] [-l login_program] [-t timeout] [-I initstring] baud_rate,... line [termtype]\nor\t[-hiLmw] [-l login_program] [-t timeout] [-I initstring] line baud_rate,... [termtype]";
1144 fprintf(stderr
, "Usage: %s %s\n", progname
, msg
);
1148 /* error - report errors to console or syslog; only understands %s and %m */
1150 #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
1166 * If the diagnostic is reported via syslog(3), the process name is
1167 * automatically prepended to the message. If we write directly to
1168 * /dev/console, we must prepend the process name ourselves.
1175 (void) str2cpy(buf
, progname
, ": ");
1176 bp
= buf
+ strlen(buf
);
1180 * %s expansion is done by hand. On a System V Release 2 system without
1181 * shared libraries and without syslog(3), linking with the the stdio
1182 * library would make the program three times as big...
1184 * %m expansion is done here as well. Too bad syslog(3) does not have a
1185 * vsprintf() like interface.
1189 fmt
= va_arg(ap
, char *);
1191 if (strncmp(fmt
, "%s", 2) == 0) {
1192 (void) strcpy(bp
, va_arg(ap
, char *));
1195 } else if (strncmp(fmt
, "%m", 2) == 0) {
1196 (void) strcpy(bp
, sys_errlist
[errno
]);
1207 * Write the diagnostic directly to /dev/console if we do not use the
1208 * syslog(3) facility.
1212 (void) openlog(progname
, LOG_PID
, LOG_AUTHPRIV
);
1213 (void) syslog(LOG_ERR
, "%s", buf
);
1216 /* Terminate with CR-LF since the console mode is unknown. */
1217 (void) strcat(bp
, "\r\n");
1218 if ((fd
= open("/dev/console", 1)) >= 0) {
1219 (void) write(fd
, buf
, strlen(buf
));
1223 (void) sleep((unsigned) 10); /* be kind to init(8) */