]>
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
8 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
9 - added Native Language Support
11 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
12 - enable hardware flow control before displaying /etc/issue
20 #include <sys/ioctl.h>
24 #include <sys/types.h>
36 #include "pathnames.h"
37 #include <sys/param.h>
41 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
48 * Some heuristics to find out what environment we are in: if it is not
49 * System V, assume it is SunOS 4.
52 #ifdef LOGIN_PROCESS /* defined in System V utmp.h */
53 #define SYSV_STYLE /* select System V style getty */
57 * Things you may want to modify.
59 * If ISSUE is not defined, agetty will never display the contents of the
60 * /etc/issue file. You will not want to spit out large "issue" files at the
61 * wrong baud rate. Relevant for System V only.
63 * You may disagree with the default line-editing etc. characters defined
64 * below. Note, however, that DEL cannot be used for interrupt generation
65 * and for line editing at the same time.
69 #define ISSUE "/etc/issue" /* displayed before the login prompt */
70 #include <sys/utsname.h>
74 #define LOGIN " login: " /* login prompt */
76 /* Some shorthands for control characters. */
78 #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
79 #define CR CTL('M') /* carriage return */
80 #define NL CTL('J') /* line feed */
81 #define BS CTL('H') /* back space */
82 #define DEL CTL('?') /* delete */
84 /* Defaults for line-editing etc. characters; you may want to change this. */
86 #define DEF_ERASE DEL /* default erase character */
87 #define DEF_INTR CTL('C') /* default interrupt character */
88 #define DEF_QUIT CTL('\\') /* default quit char */
89 #define DEF_KILL CTL('U') /* default kill char */
90 #define DEF_EOF CTL('D') /* default EOF char */
92 #define DEF_SWITCH 0 /* default switch char */
95 * SunOS 4.1.1 termio is broken. We must use the termios stuff instead,
96 * because the termio -> termios translation does not clear the termios
97 * CIBAUD bits. Therefore, the tty driver would sometimes report that input
98 * baud rate != output baud rate. I did not notice that problem with SunOS
99 * 4.1. We will use termios where available, and termio otherwise.
102 /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set
103 properly, but all is well if we use termios?! */
109 #define termio termios
110 #define TCGETA TCGETS
111 #define TCSETA TCSETS
112 #define TCSETAW TCSETSW
116 * This program tries to not use the standard-i/o library. This keeps the
117 * executable small on systems that do not have shared libraries (System V
125 * When multiple baud rates are specified on the command line, the first one
126 * we will try is the first one specified.
129 #define FIRST_SPEED 0
131 /* Storage for command-line options. */
133 #define MAX_SPEED 10 /* max. nr. of baud rates */
136 int flags
; /* toggle switches, see below */
137 int timeout
; /* time-out period */
138 char *login
; /* login program */
139 char *tty
; /* name of tty */
140 char *initstring
; /* modem init string */
141 char *issue
; /* alternative issue file */
142 int numspeed
; /* number of baud rates to try */
143 int speeds
[MAX_SPEED
]; /* baud rates to be tried */
146 #define F_PARSE (1<<0) /* process modem status messages */
147 #define F_ISSUE (1<<1) /* display /etc/issue */
148 #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
149 #define F_LOCAL (1<<3) /* force local */
150 #define F_INITSTRING (1<<4) /* initstring is set */
151 #define F_WAITCRLF (1<<5) /* wait for CR or LF */
152 #define F_CUSTISSUE (1<<6) /* give alternative issue file */
153 #define F_NOPROMPT (1<<7) /* don't ask for login name! */
155 /* Storage for things detected while the login name was read. */
158 int erase
; /* erase character */
159 int kill
; /* kill character */
160 int eol
; /* end-of-line character */
161 int parity
; /* what parity did we see */
162 int capslock
; /* upper case without lower case */
165 /* Initial values for the above. */
167 struct chardata init_chardata
= {
168 DEF_ERASE
, /* default erase character */
169 DEF_KILL
, /* default kill character */
170 13, /* default eol char */
171 0, /* space parity */
180 static struct Speedtab speedtab
[] = {
219 int main
P_((int argc
, char **argv
));
220 void parse_args
P_((int argc
, char **argv
, struct options
*op
));
221 void parse_speeds
P_((struct options
*op
, char *arg
));
222 void update_utmp
P_((char *line
));
223 void open_tty
P_((char *tty
, struct termio
*tp
, int local
));
224 void termio_init
P_((struct termio
*tp
, int speed
, struct options
*op
));
225 void auto_baud
P_((struct termio
*tp
));
226 void do_prompt
P_((struct options
*op
, struct termio
*tp
));
227 void next_speed
P_((struct termio
*tp
, struct options
*op
));
228 char *get_logname
P_((struct options
*op
, struct chardata
*cp
, struct termio
*tp
));
229 void termio_final
P_((struct options
*op
, struct termio
*tp
, struct chardata
*cp
));
230 int caps_lock
P_((char *s
));
231 int bcode
P_((char *s
));
232 void usage
P_((void));
233 void error
P_((const char *, ...));
236 /* The following is used for understandable diagnostics. */
240 /* Fake hostname for ut_host specified on command line. */
241 char *fakehost
= NULL
;
245 #define debug(s) fprintf(dbf,s); fflush(dbf)
248 #define debug(s) /* nothing */
256 char *logname
= NULL
; /* login name, given to /bin/login */
257 struct chardata chardata
; /* set by get_logname() */
258 struct termio termio
; /* terminal mode bits */
259 static struct options options
= {
260 F_ISSUE
, /* show /etc/issue (SYSV_STYLE) */
262 _PATH_LOGIN
, /* default login program */
263 "tty1", /* default tty line */
264 "", /* modem init string */
265 ISSUE
, /* default issue file */
266 0, /* no baud rates known yet */
269 setlocale(LC_ALL
, "");
270 bindtextdomain(PACKAGE
, LOCALEDIR
);
273 /* The BSD-style init command passes us a useless process name. */
282 dbf
= fopen("/dev/ttyp0", "w");
286 for(i
= 1; i
< argc
; i
++) {
292 /* Parse command-line arguments. */
294 parse_args(argc
, argv
, &options
);
300 /* Update the utmp file. */
303 update_utmp(options
.tty
);
306 debug(_("calling open_tty\n"));
307 /* Open the tty as standard { input, output, error }. */
308 open_tty(options
.tty
, &termio
, options
.flags
& F_LOCAL
);
315 (void) ioctl(0, TIOCSPGRP
, &iv
);
318 /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
319 debug(_("calling termio_init\n"));
320 termio_init(&termio
, options
.speeds
[FIRST_SPEED
], &options
);
322 /* write the modem init string and DON'T flush the buffers */
323 if (options
.flags
& F_INITSTRING
) {
324 debug(_("writing init string\n"));
325 write(1, options
.initstring
, strlen(options
.initstring
));
328 if (!(options
.flags
& F_LOCAL
)) {
329 /* go to blocking write mode unless -L is specified */
330 fcntl(1, F_SETFL
, fcntl(1, F_GETFL
, 0) & ~O_NONBLOCK
);
333 /* Optionally detect the baud rate from the modem status message. */
334 debug(_("before autobaud\n"));
335 if (options
.flags
& F_PARSE
)
338 /* Set the optional timer. */
340 (void) alarm((unsigned) options
.timeout
);
342 /* optionally wait for CR or LF before writing /etc/issue */
343 if (options
.flags
& F_WAITCRLF
) {
346 debug(_("waiting for cr-lf\n"));
347 while(read(0, &ch
, 1) == 1) {
348 ch
&= 0x7f; /* strip "parity bit" */
350 fprintf(dbf
, _("read %c\n"), ch
);
352 if (ch
== '\n' || ch
== '\r') break;
356 chardata
= init_chardata
;
357 if (!(options
.flags
& F_NOPROMPT
)) {
358 /* Read the login name. */
359 debug(_("reading login name\n"));
360 while ((logname
= get_logname(&options
, &chardata
, &termio
)) == 0)
361 next_speed(&termio
, &options
);
369 /* Finalize the termio settings. */
371 termio_final(&options
, &termio
, &chardata
);
373 /* Now the newline character should be properly written. */
375 (void) write(1, "\n", 1);
377 /* Let the login program take care of password validation. */
379 (void) execl(options
.login
, options
.login
, "--", logname
, (char *) 0);
380 error(_("%s: can't exec %s: %m"), options
.tty
, options
.login
);
381 exit(0); /* quiet GCC */
384 /* parse-args - parse command-line arguments */
387 parse_args(argc
, argv
, op
)
392 extern char *optarg
; /* getopt */
393 extern int optind
; /* getopt */
396 while (isascii(c
= getopt(argc
, argv
, "I:LH:f:hil:mt:wn"))) {
399 if (!(op
->initstring
= malloc(strlen(optarg
)))) {
400 error(_("can't malloc initstring"));
407 /* copy optarg into op->initstring decoding \ddd
408 octal codes into chars */
412 if (*p
== '\\') { /* know \\ means \ */
417 } else { /* handle \000 - \177 */
419 for (i
= 1; i
<= 3; i
++) {
420 if (*p
>= '0' && *p
<= '7') {
435 op
->flags
|= F_INITSTRING
;
438 case 'L': /* force local */
439 op
->flags
|= F_LOCAL
;
441 case 'H': /* fake login host */
444 case 'f': /* custom issue file */
445 op
->flags
|= F_CUSTISSUE
;
448 case 'h': /* enable h/w flow control */
449 op
->flags
|= F_RTSCTS
;
451 case 'i': /* do not show /etc/issue */
452 op
->flags
&= ~F_ISSUE
;
455 op
->login
= optarg
; /* non-default login program */
457 case 'm': /* parse modem status message */
458 op
->flags
|= F_PARSE
;
461 op
->flags
|= F_NOPROMPT
;
463 case 't': /* time out */
464 if ((op
->timeout
= atoi(optarg
)) <= 0)
465 error(_("bad timeout value: %s"), optarg
);
468 op
->flags
|= F_WAITCRLF
;
474 debug(_("after getopt loop\n"));
475 if (argc
< optind
+ 2) /* check parameter count */
478 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
479 if('0' <= argv
[optind
][0] && argv
[optind
][0] <= '9') {
480 /* a number first, assume it's a speed (BSD style) */
481 parse_speeds(op
, argv
[optind
++]); /* baud rate(s) */
482 op
->tty
= argv
[optind
]; /* tty name */
484 op
->tty
= argv
[optind
++]; /* tty name */
485 parse_speeds(op
, argv
[optind
]); /* baud rate(s) */
489 if (argc
> optind
&& argv
[optind
])
490 setenv ("TERM", argv
[optind
], 1);
492 #ifdef DO_DEVFS_FIDDLING
494 * some devfs junk, following Goswin Brederlow:
495 * turn ttyS<n> into tts/<n>
496 * turn tty<n> into vc/<n>
498 if (op
->tty
&& strlen(op
->tty
) < 90) {
502 if (strncmp(op
->tty
, "ttyS", 4) == 0) {
503 strcpy(dev_name
, "/dev/");
504 strcat(dev_name
, op
->tty
);
505 if (stat(dev_name
, &st
) < 0) {
506 strcpy(dev_name
, "/dev/tts/");
507 strcat(dev_name
, op
->tty
+ 4);
508 if (stat(dev_name
, &st
) == 0)
509 op
->tty
= strdup(dev_name
+ 5);
511 } else if (strncmp(op
->tty
, "tty", 3) == 0) {
512 strcpy(dev_name
, "/dev/");
513 strncat(dev_name
, op
->tty
, 90);
514 if (stat(dev_name
, &st
) < 0) {
515 strcpy(dev_name
, "/dev/vc/");
516 strcat(dev_name
, op
->tty
+ 3);
517 if (stat(dev_name
, &st
) == 0)
518 op
->tty
= strdup(dev_name
+ 5);
524 debug(_("exiting parseargs\n"));
527 /* parse_speeds - parse alternate baud rates */
530 parse_speeds(op
, arg
)
536 debug(_("entered parse_speeds\n"));
537 for (cp
= strtok(arg
, ","); cp
!= 0; cp
= strtok((char *) 0, ",")) {
538 if ((op
->speeds
[op
->numspeed
++] = bcode(cp
)) <= 0)
539 error(_("bad speed: %s"), cp
);
540 if (op
->numspeed
>= MAX_SPEED
)
541 error(_("too many alternate speeds"));
543 debug(_("exiting parsespeeds\n"));
548 /* update_utmp - update our utmp entry */
555 int mypid
= getpid();
559 * The utmp file holds miscellaneous information about things started by
560 * /sbin/init and other system-related events. Our purpose is to update
561 * the utmp entry for the current process, in particular the process type
562 * and the tty line we are listening to. Return successfully only if the
563 * utmp file can be opened for update, and if we are able to find our
564 * entry in the utmp file.
567 utmpname(_PATH_UTMP
);
569 while ((utp
= getutent())
570 && !(utp
->ut_type
== INIT_PROCESS
571 && utp
->ut_pid
== mypid
)) /* nothing */;
574 memcpy(&ut
, utp
, sizeof(ut
));
576 /* some inits don't initialize utmp... */
577 memset(&ut
, 0, sizeof(ut
));
578 strncpy(ut
.ut_id
, line
+ 3, sizeof(ut
.ut_id
));
581 strncpy(ut
.ut_user
, "LOGIN", sizeof(ut
.ut_user
));
582 strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
584 strncpy(ut
.ut_host
, fakehost
, sizeof(ut
.ut_host
));
587 ut
.ut_type
= LOGIN_PROCESS
;
595 updwtmp(_PATH_WTMP
, &ut
);
600 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
602 if ((ut_fd
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
603 write(ut_fd
, &ut
, sizeof(ut
));
615 /* open_tty - set up tty as standard { input, output, error } */
617 open_tty(tty
, tp
, local
)
622 /* Get rid of the present standard { output, error} if any. */
626 errno
= 0; /* ignore above errors */
628 /* Set up new standard input, unless we are given an already opened port. */
630 if (strcmp(tty
, "-")) {
633 /* Sanity checks... */
636 error(_("/dev: chdir() failed: %m"));
637 if (stat(tty
, &st
) < 0)
638 error("/dev/%s: %m", tty
);
639 if ((st
.st_mode
& S_IFMT
) != S_IFCHR
)
640 error(_("/dev/%s: not a character device"), tty
);
642 /* Open the tty as standard input. */
645 errno
= 0; /* ignore close(2) errors */
647 debug(_("open(2)\n"));
648 if (open(tty
, O_RDWR
|O_NONBLOCK
, 0) != 0)
649 error(_("/dev/%s: cannot open as standard input: %m"), tty
);
654 * Standard input should already be connected to an open port. Make
655 * sure it is open for read/write.
658 if ((fcntl(0, F_GETFL
, 0) & O_RDWR
) != O_RDWR
)
659 error(_("%s: not open for read/write"), tty
);
662 /* Set up standard output and standard error file descriptors. */
663 debug(_("duping\n"));
664 if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */
665 error(_("%s: dup problem: %m"), tty
); /* we have a problem */
668 * The following ioctl will fail if stdin is not a tty, but also when
669 * there is noise on the modem control lines. In the latter case, the
670 * common course of action is (1) fix your cables (2) give the modem more
671 * time to properly reset after hanging up. SunOS users can achieve (2)
672 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
673 * 5 seconds seems to be a good value.
676 if (ioctl(0, TCGETA
, tp
) < 0)
677 error("%s: ioctl: %m", tty
);
680 * It seems to be a terminal. Set proper protections and ownership. Mode
681 * 0622 is suitable for SYSV <4 because /bin/login does not change
682 * protections. SunOS 4 login will change the protections to 0620 (write
683 * access for group tty) after the login has succeeded.
686 (void) chown(tty
, 0, 0); /* root, sys */
687 (void) chmod(tty
, 0622); /* crw--w--w- */
688 errno
= 0; /* ignore above errors */
691 /* termio_init - initialize termio settings */
697 termio_init(tp
, speed
, op
)
704 * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
705 * Special characters are set after we have read the login name; all
706 * reads will be done in raw mode anyway. Errors will be dealt with
710 /* flush input and output queues, important for modems! */
711 (void) ioctl(0, TCFLSH
, TCIOFLUSH
);
714 tp
->c_cflag
= CS8
| HUPCL
| CREAD
| speed
;
715 if (op
->flags
& F_LOCAL
) {
716 tp
->c_cflag
|= CLOCAL
;
719 tp
->c_iflag
= tp
->c_lflag
= tp
->c_oflag
= tp
->c_line
= 0;
723 /* Optionally enable hardware flow control */
726 if (op
->flags
& F_RTSCTS
)
727 tp
->c_cflag
|= CRTSCTS
;
730 (void) ioctl(0, TCSETA
, tp
);
732 /* go to blocking input even in local mode */
733 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
, 0) & ~O_NONBLOCK
);
735 debug(_("term_io 2\n"));
738 /* auto_baud - extract baud rate from modem status message */
751 * This works only if the modem produces its status code AFTER raising
752 * the DCD line, and if the computer is fast enough to set the proper
753 * baud rate before the message has gone by. We expect a message of the
756 * <junk><number><junk>
758 * The number is interpreted as the baud rate of the incoming call. If the
759 * modem does not tell us the baud rate within one second, we will keep
760 * using the current baud rate. It is advisable to enable BREAK
761 * processing (comma-separated list of baud rates) if the processing of
762 * modem status messages is enabled.
766 * Use 7-bit characters, don't block if input queue is empty. Errors will
767 * be dealt with lateron.
771 tp
->c_iflag
|= ISTRIP
; /* enable 8th-bit stripping */
772 vmin
= tp
->c_cc
[VMIN
];
773 tp
->c_cc
[VMIN
] = 0; /* don't block if queue empty */
774 (void) ioctl(0, TCSETA
, tp
);
777 * Wait for a while, then read everything the modem has said so far and
778 * try to extract the speed of the dial-in call.
782 if ((nread
= read(0, buf
, sizeof(buf
) - 1)) > 0) {
784 for (bp
= buf
; bp
< buf
+ nread
; bp
++) {
785 if (isascii(*bp
) && isdigit(*bp
)) {
786 if ((speed
= bcode(bp
))) {
787 tp
->c_cflag
&= ~CBAUD
;
788 tp
->c_cflag
|= speed
;
794 /* Restore terminal settings. Errors will be dealt with lateron. */
797 tp
->c_cc
[VMIN
] = vmin
;
798 (void) ioctl(0, TCSETA
, tp
);
801 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
816 (void) write(1, "\r\n", 2); /* start a new line */
817 #ifdef ISSUE /* optional: show /etc/issue */
818 if ((op
->flags
& F_ISSUE
) && (fd
= fopen(op
->issue
, "r"))) {
819 oflag
= tp
->c_oflag
; /* save current setting */
820 tp
->c_oflag
|= (ONLCR
| OPOST
); /* map NL in output to CR-NL */
821 (void) ioctl(0, TCSETAW
, tp
);
824 while ((c
= getc(fd
)) != EOF
)
833 (void) printf ("%s", uts
.sysname
);
837 (void) printf ("%s", uts
.nodename
);
841 (void) printf ("%s", uts
.release
);
845 (void) printf ("%s", uts
.version
);
849 (void) printf ("%s", uts
.machine
);
854 char domainname
[256];
855 #ifdef HAVE_getdomainname
856 getdomainname(domainname
, sizeof(domainname
));
858 strcpy(domainname
, "unknown_domain");
860 domainname
[sizeof(domainname
)-1] = '\0';
861 printf ("%s", domainname
);
868 char *weekday
[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
870 char *month
[] = { "Jan", "Feb", "Mar", "Apr", "May",
871 "Jun", "Jul", "Aug", "Sep", "Oct",
877 tm
= localtime(&now
);
880 (void) printf ("%s %s %d %d",
881 weekday
[tm
->tm_wday
], month
[tm
->tm_mon
],
883 tm
->tm_year
< 70 ? tm
->tm_year
+ 2000 :
886 (void) printf ("%02d:%02d:%02d",
887 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
893 (void) printf ("%s", op
->tty
);
900 for (i
= 0; speedtab
[i
].speed
; i
++) {
901 if (speedtab
[i
].code
== (tp
->c_cflag
& CBAUD
)) {
902 printf("%ld", speedtab
[i
].speed
);
914 while ((ut
= getutent()))
915 if (ut
->ut_type
== USER_PROCESS
)
918 printf ("%d ", users
);
920 printf ((users
== 1) ? _("user") : _("users"));
932 tp
->c_oflag
= oflag
; /* restore settings */
933 (void) ioctl(0, TCSETAW
, tp
); /* wait till output is gone */
939 char hn
[MAXHOSTNAMELEN
+1];
941 (void) gethostname(hn
, MAXHOSTNAMELEN
);
942 write(1, hn
, strlen(hn
));
945 (void) write(1, LOGIN
, sizeof(LOGIN
) - 1); /* always show login prompt */
948 /* next_speed - select next baud rate */
954 static int baud_index
= FIRST_SPEED
;/* current speed index */
956 baud_index
= (baud_index
+ 1) % op
->numspeed
;
957 tp
->c_cflag
&= ~CBAUD
;
958 tp
->c_cflag
|= op
->speeds
[baud_index
];
959 (void) ioctl(0, TCSETA
, tp
);
962 /* get_logname - get user name, establish parity, speed, erase, kill, eol */
964 char *get_logname(op
, cp
, tp
)
969 static char logname
[BUFSIZ
];
971 char c
; /* input character, full eight bits */
972 char ascval
; /* low 7 bits of input character */
973 int bits
; /* # of "1" bits per character */
974 int mask
; /* mask with 1 bit up */
975 static char *erase
[] = { /* backspace-space-backspace */
976 "\010\040\010", /* space parity */
977 "\010\040\010", /* odd parity */
978 "\210\240\210", /* even parity */
979 "\210\240\210", /* no parity */
982 /* Initialize kill, erase, parity etc. (also after switching speeds). */
986 /* Flush pending input (esp. after parsing or switching the baud rate). */
989 (void) ioctl(0, TCFLSH
, TCIFLUSH
);
991 /* Prompt for and read a login name. */
993 for (*logname
= 0; *logname
== 0; /* void */ ) {
995 /* Write issue file and prompt, with "parity" bit == 0. */
999 /* Read name, watch for break, parity, erase, kill, end-of-line. */
1001 for (bp
= logname
, cp
->eol
= 0; cp
->eol
== 0; /* void */ ) {
1003 /* Do not report trivial EINTR/EIO errors. */
1005 if (read(0, &c
, 1) < 1) {
1006 if (errno
== EINTR
|| errno
== EIO
)
1008 error(_("%s: read: %m"), op
->tty
);
1010 /* Do BREAK handling elsewhere. */
1012 if ((c
== 0) && op
->numspeed
> 1)
1015 /* Do parity bit handling. */
1017 if (c
!= (ascval
= (c
& 0177))) { /* "parity" bit on ? */
1018 for (bits
= 1, mask
= 1; mask
& 0177; mask
<<= 1)
1020 bits
++; /* count "1" bits */
1021 cp
->parity
|= ((bits
& 1) ? 1 : 2);
1023 /* Do erase, kill and end-of-line processing. */
1028 *bp
= 0; /* terminate logname */
1029 cp
->eol
= ascval
; /* set end-of-line char */
1034 cp
->erase
= ascval
; /* set erase character */
1036 (void) write(1, erase
[cp
->parity
], 3);
1042 cp
->kill
= ascval
; /* set kill character */
1043 while (bp
> logname
) {
1044 (void) write(1, erase
[cp
->parity
], 3);
1051 if (!isascii(ascval
) || !isprint(ascval
)) {
1052 /* ignore garbage characters */ ;
1053 } else if (bp
- logname
>= sizeof(logname
) - 1) {
1054 error(_("%s: input overrun"), op
->tty
);
1056 (void) write(1, &c
, 1); /* echo the character */
1057 *bp
++ = ascval
; /* and store it */
1063 /* Handle names with upper case and no lower case. */
1065 if ((cp
->capslock
= caps_lock(logname
))) {
1066 for (bp
= logname
; *bp
; bp
++)
1068 *bp
= tolower(*bp
); /* map name to lower case */
1073 /* termio_final - set the final tty mode bits */
1075 termio_final(op
, tp
, cp
)
1078 struct chardata
*cp
;
1080 /* General terminal-independent stuff. */
1082 tp
->c_iflag
|= IXON
| IXOFF
; /* 2-way flow control */
1083 tp
->c_lflag
|= ICANON
| ISIG
| ECHO
| ECHOE
| ECHOK
| ECHOKE
;
1084 /* no longer| ECHOCTL | ECHOPRT*/
1085 tp
->c_oflag
|= OPOST
;
1086 /* tp->c_cflag = 0; */
1087 tp
->c_cc
[VINTR
] = DEF_INTR
; /* default interrupt */
1088 tp
->c_cc
[VQUIT
] = DEF_QUIT
; /* default quit */
1089 tp
->c_cc
[VEOF
] = DEF_EOF
; /* default EOF character */
1090 tp
->c_cc
[VEOL
] = DEF_EOL
;
1092 tp
->c_cc
[VSWTC
] = DEF_SWITCH
; /* default switch character */
1094 tp
->c_cc
[VSWTCH
] = DEF_SWITCH
; /* default switch character */
1097 /* Account for special characters seen in input. */
1099 if (cp
->eol
== CR
) {
1100 tp
->c_iflag
|= ICRNL
; /* map CR in input to NL */
1101 tp
->c_oflag
|= ONLCR
; /* map NL in output to CR-NL */
1103 tp
->c_cc
[VERASE
] = cp
->erase
; /* set erase character */
1104 tp
->c_cc
[VKILL
] = cp
->kill
; /* set kill character */
1106 /* Account for the presence or absence of parity bits in input. */
1108 switch (cp
->parity
) {
1109 case 0: /* space (always 0) parity */
1111 case 1: /* odd parity */
1112 tp
->c_cflag
|= PARODD
;
1114 case 2: /* even parity */
1115 tp
->c_cflag
|= PARENB
;
1116 tp
->c_iflag
|= INPCK
| ISTRIP
;
1118 case (1 | 2): /* no parity bit */
1119 tp
->c_cflag
&= ~CSIZE
;
1123 /* Account for upper case without lower case. */
1126 tp
->c_iflag
|= IUCLC
;
1127 tp
->c_lflag
|= XCASE
;
1128 tp
->c_oflag
|= OLCUC
;
1130 /* Optionally enable hardware flow control */
1133 if (op
->flags
& F_RTSCTS
)
1134 tp
->c_cflag
|= CRTSCTS
;
1137 /* Finally, make the new settings effective */
1139 if (ioctl(0, TCSETA
, tp
) < 0)
1140 error("%s: ioctl: TCSETA: %m", op
->tty
);
1143 /* caps_lock - string contains upper case without lower case */
1150 for (capslock
= 0; *s
; s
++) {
1154 capslock
= isupper(*s
);
1159 /* bcode - convert speed string to speed code; return 0 on failure */
1164 struct Speedtab
*sp
;
1165 long speed
= atol(s
);
1167 for (sp
= speedtab
; sp
->speed
; sp
++)
1168 if (sp
->speed
== speed
)
1173 /* usage - explain */
1178 fprintf(stderr
, _("Usage: %s [-hiLmw] [-l login_program] [-t timeout] [-I initstring] [-H login_host] baud_rate,... line [termtype]\nor\t[-hiLmw] [-l login_program] [-t timeout] [-I initstring] [-H login_host] line baud_rate,... [termtype]\n"), progname
);
1182 /* error - report errors to console or syslog; only understands %s and %m */
1184 #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
1187 error(const char *fmt
, ...) {
1196 * If the diagnostic is reported via syslog(3), the process name is
1197 * automatically prepended to the message. If we write directly to
1198 * /dev/console, we must prepend the process name ourselves.
1205 (void) str2cpy(buf
, progname
, ": ");
1206 bp
= buf
+ strlen(buf
);
1210 * %s expansion is done by hand. On a System V Release 2 system without
1211 * shared libraries and without syslog(3), linking with the the stdio
1212 * library would make the program three times as big...
1214 * %m expansion is done here as well. Too bad syslog(3) does not have a
1215 * vsprintf() like interface.
1220 if (strncmp(fmt
, "%s", 2) == 0) {
1221 (void) strcpy(bp
, va_arg(ap
, char *));
1224 } else if (strncmp(fmt
, "%m", 2) == 0) {
1225 (void) strcpy(bp
, strerror(errno
));
1236 * Write the diagnostic directly to /dev/console if we do not use the
1237 * syslog(3) facility.
1241 (void) openlog(progname
, LOG_PID
, LOG_AUTHPRIV
);
1242 (void) syslog(LOG_ERR
, "%s", buf
);
1245 /* Terminate with CR-LF since the console mode is unknown. */
1246 (void) strcat(bp
, "\r\n");
1247 if ((fd
= open("/dev/console", 1)) >= 0) {
1248 (void) write(fd
, buf
, strlen(buf
));
1252 (void) sleep((unsigned) 10); /* be kind to init(8) */