Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* agetty.c - another getty program for Linux. By W. Z. Venema 1989 |
"Robert P. J. Day" | 801ab14 | 2006-07-12 07:56:04 +0000 | [diff] [blame] | 3 | * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> |
| 4 | * This program is freely distributable. The entire man-page used to |
| 5 | * be here. Now read the real man-page agetty.8 instead. |
| 6 | * |
| 7 | * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 |
| 8 | * |
| 9 | * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> |
| 10 | * - added Native Language Support |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 11 | |
"Robert P. J. Day" | 801ab14 | 2006-07-12 07:56:04 +0000 | [diff] [blame] | 12 | * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> |
| 13 | * - enable hardware flow control before displaying /etc/issue |
| 14 | * |
| 15 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| 16 | * |
| 17 | */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 18 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 19 | #include "busybox.h" |
Denis Vlasenko | f702652 | 2006-09-19 13:50:55 +0000 | [diff] [blame] | 20 | #include <syslog.h> |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 21 | |
Mike Frysinger | b381009 | 2005-07-01 01:29:44 +0000 | [diff] [blame] | 22 | #ifdef CONFIG_FEATURE_UTMP |
| 23 | #include <utmp.h> |
| 24 | #endif |
| 25 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 26 | #define _PATH_LOGIN "/bin/login" |
| 27 | |
Glenn L McGrath | cb66509 | 2003-02-08 22:33:53 +0000 | [diff] [blame] | 28 | #ifdef CONFIG_SYSLOGD |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 29 | #include <sys/param.h> |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 30 | #endif |
| 31 | |
| 32 | |
| 33 | /* |
| 34 | * Some heuristics to find out what environment we are in: if it is not |
| 35 | * System V, assume it is SunOS 4. |
| 36 | */ |
| 37 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 38 | #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ |
| 39 | #define SYSV_STYLE /* select System V style getty */ |
Mike Frysinger | 8deb686 | 2005-07-01 01:04:32 +0000 | [diff] [blame] | 40 | #ifdef CONFIG_FEATURE_WTMP |
Eric Andersen | fdfe298 | 2002-10-10 03:55:09 +0000 | [diff] [blame] | 41 | extern void updwtmp(const char *filename, const struct utmp *ut); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 42 | #endif |
Eric Andersen | fdfe298 | 2002-10-10 03:55:09 +0000 | [diff] [blame] | 43 | #endif /* LOGIN_PROCESS */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 44 | |
| 45 | /* |
| 46 | * Things you may want to modify. |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 47 | * |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 48 | * You may disagree with the default line-editing etc. characters defined |
| 49 | * below. Note, however, that DEL cannot be used for interrupt generation |
| 50 | * and for line editing at the same time. |
| 51 | */ |
| 52 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 53 | #ifdef SYSV_STYLE |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 54 | #include <sys/utsname.h> |
| 55 | #include <time.h> |
| 56 | #endif |
| 57 | |
Eric Andersen | 77804ce | 2005-07-27 06:05:38 +0000 | [diff] [blame] | 58 | /* If ISSUE is not defined, agetty will never display the contents of the |
| 59 | * /etc/issue file. You will not want to spit out large "issue" files at the |
| 60 | * wrong baud rate. |
| 61 | */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 62 | #define ISSUE "/etc/issue" /* displayed before the login prompt */ |
Eric Andersen | 77804ce | 2005-07-27 06:05:38 +0000 | [diff] [blame] | 63 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 64 | /* Some shorthands for control characters. */ |
| 65 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 66 | #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ |
| 67 | #define CR CTL('M') /* carriage return */ |
| 68 | #define NL CTL('J') /* line feed */ |
| 69 | #define BS CTL('H') /* back space */ |
| 70 | #define DEL CTL('?') /* delete */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 71 | |
| 72 | /* Defaults for line-editing etc. characters; you may want to change this. */ |
| 73 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 74 | #define DEF_ERASE DEL /* default erase character */ |
| 75 | #define DEF_INTR CTL('C') /* default interrupt character */ |
| 76 | #define DEF_QUIT CTL('\\') /* default quit char */ |
| 77 | #define DEF_KILL CTL('U') /* default kill char */ |
| 78 | #define DEF_EOF CTL('D') /* default EOF char */ |
| 79 | #define DEF_EOL '\n' |
| 80 | #define DEF_SWITCH 0 /* default switch char */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 81 | |
| 82 | /* |
| 83 | * SunOS 4.1.1 termio is broken. We must use the termios stuff instead, |
| 84 | * because the termio -> termios translation does not clear the termios |
| 85 | * CIBAUD bits. Therefore, the tty driver would sometimes report that input |
| 86 | * baud rate != output baud rate. I did not notice that problem with SunOS |
| 87 | * 4.1. We will use termios where available, and termio otherwise. |
| 88 | */ |
| 89 | |
| 90 | /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set |
| 91 | properly, but all is well if we use termios?! */ |
| 92 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 93 | #ifdef TCGETS |
| 94 | #undef TCGETA |
| 95 | #undef TCSETA |
| 96 | #undef TCSETAW |
| 97 | #define termio termios |
| 98 | #define TCGETA TCGETS |
| 99 | #define TCSETA TCSETS |
| 100 | #define TCSETAW TCSETSW |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 101 | #endif |
| 102 | |
| 103 | /* |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 104 | * When multiple baud rates are specified on the command line, the first one |
| 105 | * we will try is the first one specified. |
| 106 | */ |
| 107 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 108 | #define FIRST_SPEED 0 |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 109 | |
| 110 | /* Storage for command-line options. */ |
| 111 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 112 | #define MAX_SPEED 10 /* max. nr. of baud rates */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 113 | |
| 114 | struct options { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 115 | int flags; /* toggle switches, see below */ |
| 116 | int timeout; /* time-out period */ |
| 117 | char *login; /* login program */ |
| 118 | char *tty; /* name of tty */ |
| 119 | char *initstring; /* modem init string */ |
| 120 | char *issue; /* alternative issue file */ |
| 121 | int numspeed; /* number of baud rates to try */ |
| 122 | int speeds[MAX_SPEED]; /* baud rates to be tried */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 123 | }; |
| 124 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 125 | static const char opt_string[] = "I:LH:f:hil:mt:wn"; |
| 126 | #define F_INITSTRING (1<<0) /* initstring is set */ |
| 127 | #define F_LOCAL (1<<1) /* force local */ |
| 128 | #define F_FAKEHOST (1<<2) /* force fakehost */ |
| 129 | #define F_CUSTISSUE (1<<3) /* give alternative issue file */ |
| 130 | #define F_RTSCTS (1<<4) /* enable RTS/CTS flow control */ |
| 131 | #define F_ISSUE (1<<5) /* display /etc/issue */ |
| 132 | #define F_LOGIN (1<<6) /* non-default login program */ |
| 133 | #define F_PARSE (1<<7) /* process modem status messages */ |
| 134 | #define F_TIMEOUT (1<<8) /* time out */ |
| 135 | #define F_WAITCRLF (1<<9) /* wait for CR or LF */ |
| 136 | #define F_NOPROMPT (1<<10) /* don't ask for login name! */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 137 | |
| 138 | /* Storage for things detected while the login name was read. */ |
| 139 | |
Mike Frysinger | b381009 | 2005-07-01 01:29:44 +0000 | [diff] [blame] | 140 | struct chardata { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 141 | int erase; /* erase character */ |
| 142 | int kill; /* kill character */ |
| 143 | int eol; /* end-of-line character */ |
| 144 | int parity; /* what parity did we see */ |
| 145 | int capslock; /* upper case without lower case */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 146 | }; |
| 147 | |
| 148 | /* Initial values for the above. */ |
| 149 | |
Eric Andersen | 14f5c8d | 2005-04-16 19:39:00 +0000 | [diff] [blame] | 150 | static struct chardata init_chardata = { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 151 | DEF_ERASE, /* default erase character */ |
| 152 | DEF_KILL, /* default kill character */ |
| 153 | 13, /* default eol char */ |
| 154 | 0, /* space parity */ |
| 155 | 0, /* no capslock */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 156 | }; |
| 157 | |
Manuel Novoa III | cad5364 | 2003-03-19 09:13:01 +0000 | [diff] [blame] | 158 | #if 0 |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 159 | struct Speedtab { |
| 160 | long speed; |
| 161 | int code; |
| 162 | }; |
| 163 | |
| 164 | static struct Speedtab speedtab[] = { |
| 165 | {50, B50}, |
| 166 | {75, B75}, |
| 167 | {110, B110}, |
| 168 | {134, B134}, |
| 169 | {150, B150}, |
| 170 | {200, B200}, |
| 171 | {300, B300}, |
| 172 | {600, B600}, |
| 173 | {1200, B1200}, |
| 174 | {1800, B1800}, |
| 175 | {2400, B2400}, |
| 176 | {4800, B4800}, |
| 177 | {9600, B9600}, |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 178 | #ifdef B19200 |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 179 | {19200, B19200}, |
| 180 | #endif |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 181 | #ifdef B38400 |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 182 | {38400, B38400}, |
| 183 | #endif |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 184 | #ifdef EXTA |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 185 | {19200, EXTA}, |
| 186 | #endif |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 187 | #ifdef EXTB |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 188 | {38400, EXTB}, |
| 189 | #endif |
| 190 | #ifdef B57600 |
| 191 | {57600, B57600}, |
| 192 | #endif |
| 193 | #ifdef B115200 |
| 194 | {115200, B115200}, |
| 195 | #endif |
| 196 | #ifdef B230400 |
| 197 | {230400, B230400}, |
| 198 | #endif |
| 199 | {0, 0}, |
| 200 | }; |
Manuel Novoa III | cad5364 | 2003-03-19 09:13:01 +0000 | [diff] [blame] | 201 | #endif |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 202 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 203 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 204 | #ifdef SYSV_STYLE |
Mike Frysinger | 8deb686 | 2005-07-01 01:04:32 +0000 | [diff] [blame] | 205 | #ifdef CONFIG_FEATURE_UTMP |
Eric Andersen | fdfe298 | 2002-10-10 03:55:09 +0000 | [diff] [blame] | 206 | static void update_utmp(char *line); |
| 207 | #endif |
Mike Frysinger | b381009 | 2005-07-01 01:29:44 +0000 | [diff] [blame] | 208 | #endif |
Eric Andersen | fdfe298 | 2002-10-10 03:55:09 +0000 | [diff] [blame] | 209 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 210 | /* The following is used for understandable diagnostics. */ |
| 211 | |
| 212 | /* Fake hostname for ut_host specified on command line. */ |
| 213 | static char *fakehost = NULL; |
| 214 | |
| 215 | /* ... */ |
| 216 | #ifdef DEBUGGING |
| 217 | #define debug(s) fprintf(dbf,s); fflush(dbf) |
| 218 | #define DEBUGTERM "/dev/ttyp0" |
| 219 | FILE *dbf; |
| 220 | #else |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 221 | #define debug(s) /* nothing */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 222 | #endif |
| 223 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 224 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 225 | /* bcode - convert speed string to speed code; return 0 on failure */ |
| 226 | static int bcode(const char *s) |
| 227 | { |
| 228 | int r; |
| 229 | unsigned long value; |
| 230 | if (safe_strtoul((char *)s, &value)) { |
| 231 | return -1; |
| 232 | } |
Rob Landley | 290fcb4 | 2006-06-18 23:59:03 +0000 | [diff] [blame] | 233 | if ((r = tty_value_to_baud(value)) > 0) { |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 234 | return r; |
| 235 | } |
| 236 | return 0; |
| 237 | } |
| 238 | |
| 239 | |
| 240 | /* parse_speeds - parse alternate baud rates */ |
| 241 | static void parse_speeds(struct options *op, char *arg) |
| 242 | { |
| 243 | char *cp; |
| 244 | |
| 245 | debug("entered parse_speeds\n"); |
| 246 | for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { |
| 247 | if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 248 | bb_error_msg_and_die("bad speed: %s", cp); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 249 | if (op->numspeed > MAX_SPEED) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 250 | bb_error_msg_and_die("too many alternate speeds"); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 251 | } |
| 252 | debug("exiting parsespeeds\n"); |
| 253 | } |
| 254 | |
| 255 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 256 | /* parse_args - parse command-line arguments */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 257 | static void parse_args(int argc, char **argv, struct options *op) |
| 258 | { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 259 | char *ts; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 260 | |
Denis Vlasenko | 67b23e6 | 2006-10-03 21:00:06 +0000 | [diff] [blame^] | 261 | op->flags = getopt32(argc, argv, opt_string, |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 262 | &(op->initstring), &fakehost, &(op->issue), |
| 263 | &(op->login), &ts); |
| 264 | if(op->flags & F_INITSTRING) { |
| 265 | const char *p = op->initstring; |
| 266 | char *q; |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 267 | |
Rob Landley | d921b2e | 2006-08-03 15:41:12 +0000 | [diff] [blame] | 268 | q = op->initstring = xstrdup(op->initstring); |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 269 | /* copy optarg into op->initstring decoding \ddd |
| 270 | octal codes into chars */ |
| 271 | while (*p) { |
| 272 | if (*p == '\\') { |
| 273 | p++; |
| 274 | *q++ = bb_process_escape_sequence(&p); |
| 275 | } else { |
| 276 | *q++ = *p++; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 277 | } |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 278 | } |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 279 | *q = '\0'; |
| 280 | } |
| 281 | op->flags ^= F_ISSUE; /* revert flag show /etc/issue */ |
| 282 | if(op->flags & F_TIMEOUT) { |
| 283 | if ((op->timeout = atoi(ts)) <= 0) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 284 | bb_error_msg_and_die("bad timeout value: %s", ts); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 285 | } |
| 286 | debug("after getopt loop\n"); |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 287 | if (argc < optind + 2) /* check parameter count */ |
Manuel Novoa III | cad5364 | 2003-03-19 09:13:01 +0000 | [diff] [blame] | 288 | bb_show_usage(); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 289 | |
| 290 | /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ |
| 291 | if ('0' <= argv[optind][0] && argv[optind][0] <= '9') { |
| 292 | /* a number first, assume it's a speed (BSD style) */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 293 | parse_speeds(op, argv[optind++]); /* baud rate(s) */ |
| 294 | op->tty = argv[optind]; /* tty name */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 295 | } else { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 296 | op->tty = argv[optind++]; /* tty name */ |
| 297 | parse_speeds(op, argv[optind]); /* baud rate(s) */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 298 | } |
| 299 | |
| 300 | optind++; |
| 301 | if (argc > optind && argv[optind]) |
| 302 | setenv("TERM", argv[optind], 1); |
| 303 | |
| 304 | debug("exiting parseargs\n"); |
| 305 | } |
| 306 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 307 | static void xdup2(int srcfd, int dstfd, const char *tty) |
| 308 | { |
| 309 | if(dup2(srcfd, dstfd) == -1) |
| 310 | bb_perror_msg_and_die("%s: dup", tty); |
| 311 | } |
| 312 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 313 | /* open_tty - set up tty as standard { input, output, error } */ |
| 314 | static void open_tty(char *tty, struct termio *tp, int local) |
| 315 | { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 316 | int chdir_to_root = 0; |
| 317 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 318 | /* Set up new standard input, unless we are given an already opened port. */ |
| 319 | |
| 320 | if (strcmp(tty, "-")) { |
| 321 | struct stat st; |
Mike Frysinger | b381009 | 2005-07-01 01:29:44 +0000 | [diff] [blame] | 322 | int fd; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 323 | |
| 324 | /* Sanity checks... */ |
| 325 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 326 | xchdir("/dev"); |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 327 | chdir_to_root = 1; |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 328 | xstat(tty, &st); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 329 | if ((st.st_mode & S_IFMT) != S_IFCHR) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 330 | bb_error_msg_and_die("%s: not a character device", tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 331 | |
| 332 | /* Open the tty as standard input. */ |
| 333 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 334 | debug("open(2)\n"); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 335 | fd = xopen(tty, O_RDWR | O_NONBLOCK); |
| 336 | if(fd) { |
| 337 | xdup2(fd, 0, tty); |
| 338 | close(fd); |
Denis Vlasenko | 9213a9e | 2006-09-17 16:28:10 +0000 | [diff] [blame] | 339 | } |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 340 | } else { |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 341 | /* |
| 342 | * Standard input should already be connected to an open port. Make |
| 343 | * sure it is open for read/write. |
| 344 | */ |
| 345 | |
| 346 | if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 347 | bb_error_msg_and_die("%s: not open for read/write", tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 348 | } |
| 349 | |
Mike Frysinger | b381009 | 2005-07-01 01:29:44 +0000 | [diff] [blame] | 350 | /* Replace current standard output/error fd's with new ones */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 351 | debug("duping\n"); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 352 | xdup2(0, 1, tty); |
| 353 | xdup2(0, 2, tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 354 | |
| 355 | /* |
| 356 | * The following ioctl will fail if stdin is not a tty, but also when |
| 357 | * there is noise on the modem control lines. In the latter case, the |
| 358 | * common course of action is (1) fix your cables (2) give the modem more |
| 359 | * time to properly reset after hanging up. SunOS users can achieve (2) |
| 360 | * by patching the SunOS kernel variable "zsadtrlow" to a larger value; |
| 361 | * 5 seconds seems to be a good value. |
| 362 | */ |
| 363 | |
| 364 | if (ioctl(0, TCGETA, tp) < 0) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 365 | bb_perror_msg_and_die("%s: ioctl(TCGETA)", tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 366 | |
| 367 | /* |
| 368 | * It seems to be a terminal. Set proper protections and ownership. Mode |
| 369 | * 0622 is suitable for SYSV <4 because /bin/login does not change |
| 370 | * protections. SunOS 4 login will change the protections to 0620 (write |
| 371 | * access for group tty) after the login has succeeded. |
| 372 | */ |
| 373 | |
| 374 | #ifdef DEBIAN |
| 375 | { |
| 376 | /* tty to root.dialout 660 */ |
| 377 | struct group *gr; |
| 378 | int id; |
| 379 | |
| 380 | id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0; |
| 381 | chown(tty, 0, id); |
| 382 | chmod(tty, 0660); |
| 383 | |
| 384 | /* vcs,vcsa to root.sys 600 */ |
| 385 | if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) { |
| 386 | char *vcs, *vcsa; |
| 387 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 388 | vcs = xstrdup(tty); |
| 389 | vcsa = xmalloc(strlen(tty) + 2); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 390 | strcpy(vcs, "vcs"); |
| 391 | strcpy(vcs + 3, tty + 3); |
| 392 | strcpy(vcsa, "vcsa"); |
| 393 | strcpy(vcsa + 4, tty + 3); |
| 394 | |
| 395 | id = (gr = getgrnam("sys")) ? gr->gr_gid : 0; |
| 396 | chown(vcs, 0, id); |
| 397 | chmod(vcs, 0600); |
| 398 | chown(vcsa, 0, id); |
| 399 | chmod(vcs, 0600); |
| 400 | |
| 401 | free(vcs); |
| 402 | free(vcsa); |
| 403 | } |
| 404 | } |
| 405 | #else |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 406 | (void) chown(tty, 0, 0); /* root, sys */ |
| 407 | (void) chmod(tty, 0622); /* crw--w--w- */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 408 | #endif |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 409 | if (chdir_to_root) |
| 410 | xchdir("/"); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | /* termio_init - initialize termio settings */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 414 | static void termio_init(struct termio *tp, int speed, struct options *op) |
| 415 | { |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 416 | /* |
| 417 | * Initial termio settings: 8-bit characters, raw-mode, blocking i/o. |
| 418 | * Special characters are set after we have read the login name; all |
| 419 | * reads will be done in raw mode anyway. Errors will be dealt with |
| 420 | * lateron. |
| 421 | */ |
| 422 | #ifdef __linux__ |
| 423 | /* flush input and output queues, important for modems! */ |
| 424 | (void) ioctl(0, TCFLSH, TCIOFLUSH); |
| 425 | #endif |
| 426 | |
| 427 | tp->c_cflag = CS8 | HUPCL | CREAD | speed; |
| 428 | if (op->flags & F_LOCAL) { |
| 429 | tp->c_cflag |= CLOCAL; |
| 430 | } |
| 431 | |
Rob Landley | f78ab53 | 2006-08-24 20:00:44 +0000 | [diff] [blame] | 432 | tp->c_iflag = tp->c_lflag = tp->c_line = 0; |
| 433 | tp->c_oflag = OPOST | ONLCR; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 434 | tp->c_cc[VMIN] = 1; |
| 435 | tp->c_cc[VTIME] = 0; |
| 436 | |
| 437 | /* Optionally enable hardware flow control */ |
| 438 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 439 | #ifdef CRTSCTS |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 440 | if (op->flags & F_RTSCTS) |
| 441 | tp->c_cflag |= CRTSCTS; |
| 442 | #endif |
| 443 | |
| 444 | (void) ioctl(0, TCSETA, tp); |
| 445 | |
| 446 | /* go to blocking input even in local mode */ |
| 447 | fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); |
| 448 | |
| 449 | debug("term_io 2\n"); |
| 450 | } |
| 451 | |
| 452 | /* auto_baud - extract baud rate from modem status message */ |
| 453 | static void auto_baud(struct termio *tp) |
| 454 | { |
| 455 | int speed; |
| 456 | int vmin; |
| 457 | unsigned iflag; |
| 458 | char buf[BUFSIZ]; |
| 459 | char *bp; |
| 460 | int nread; |
| 461 | |
| 462 | /* |
| 463 | * This works only if the modem produces its status code AFTER raising |
| 464 | * the DCD line, and if the computer is fast enough to set the proper |
| 465 | * baud rate before the message has gone by. We expect a message of the |
| 466 | * following format: |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 467 | * |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 468 | * <junk><number><junk> |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 469 | * |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 470 | * The number is interpreted as the baud rate of the incoming call. If the |
| 471 | * modem does not tell us the baud rate within one second, we will keep |
| 472 | * using the current baud rate. It is advisable to enable BREAK |
| 473 | * processing (comma-separated list of baud rates) if the processing of |
| 474 | * modem status messages is enabled. |
| 475 | */ |
| 476 | |
| 477 | /* |
| 478 | * Use 7-bit characters, don't block if input queue is empty. Errors will |
| 479 | * be dealt with lateron. |
| 480 | */ |
| 481 | |
| 482 | iflag = tp->c_iflag; |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 483 | tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 484 | vmin = tp->c_cc[VMIN]; |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 485 | tp->c_cc[VMIN] = 0; /* don't block if queue empty */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 486 | (void) ioctl(0, TCSETA, tp); |
| 487 | |
| 488 | /* |
| 489 | * Wait for a while, then read everything the modem has said so far and |
| 490 | * try to extract the speed of the dial-in call. |
| 491 | */ |
| 492 | |
| 493 | (void) sleep(1); |
| 494 | if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) { |
| 495 | buf[nread] = '\0'; |
| 496 | for (bp = buf; bp < buf + nread; bp++) { |
| 497 | if (isascii(*bp) && isdigit(*bp)) { |
| 498 | if ((speed = bcode(bp))) { |
| 499 | tp->c_cflag &= ~CBAUD; |
| 500 | tp->c_cflag |= speed; |
| 501 | } |
| 502 | break; |
| 503 | } |
| 504 | } |
| 505 | } |
| 506 | /* Restore terminal settings. Errors will be dealt with lateron. */ |
| 507 | |
| 508 | tp->c_iflag = iflag; |
| 509 | tp->c_cc[VMIN] = vmin; |
| 510 | (void) ioctl(0, TCSETA, tp); |
| 511 | } |
| 512 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 513 | /* next_speed - select next baud rate */ |
| 514 | static void next_speed(struct termio *tp, struct options *op) |
| 515 | { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 516 | static int baud_index = FIRST_SPEED; /* current speed index */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 517 | |
| 518 | baud_index = (baud_index + 1) % op->numspeed; |
| 519 | tp->c_cflag &= ~CBAUD; |
| 520 | tp->c_cflag |= op->speeds[baud_index]; |
| 521 | (void) ioctl(0, TCSETA, tp); |
| 522 | } |
| 523 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 524 | |
| 525 | /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ |
| 526 | static void do_prompt(struct options *op, struct termio *tp) |
| 527 | { |
| 528 | #ifdef ISSUE /* optional: show /etc/issue */ |
| 529 | print_login_issue(op->issue, op->tty); |
| 530 | #endif |
| 531 | print_login_prompt(); |
| 532 | } |
| 533 | |
| 534 | /* caps_lock - string contains upper case without lower case */ |
| 535 | /* returns 1 if true, 0 if false */ |
| 536 | static int caps_lock(const char *s) |
| 537 | { |
| 538 | int capslock; |
| 539 | |
| 540 | for (capslock = 0; *s; s++) { |
| 541 | if (islower(*s)) |
| 542 | return (0); |
| 543 | if (capslock == 0) |
| 544 | capslock = isupper(*s); |
| 545 | } |
| 546 | return (capslock); |
| 547 | } |
| 548 | |
| 549 | #define logname bb_common_bufsiz1 |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 550 | /* get_logname - get user name, establish parity, speed, erase, kill, eol */ |
| 551 | /* return NULL on failure, logname on success */ |
| 552 | static char *get_logname(struct options *op, struct chardata *cp, struct termio *tp) |
| 553 | { |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 554 | char *bp; |
"Vladimir N. Oleynik" | 6f347ef | 2005-10-15 10:23:55 +0000 | [diff] [blame] | 555 | char c; /* input character, full eight bits */ |
| 556 | char ascval; /* low 7 bits of input character */ |
| 557 | int bits; /* # of "1" bits per character */ |
| 558 | int mask; /* mask with 1 bit up */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 559 | static char *erase[] = { /* backspace-space-backspace */ |
| 560 | "\010\040\010", /* space parity */ |
| 561 | "\010\040\010", /* odd parity */ |
| 562 | "\210\240\210", /* even parity */ |
| 563 | "\210\240\210", /* no parity */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 564 | }; |
| 565 | |
| 566 | /* Initialize kill, erase, parity etc. (also after switching speeds). */ |
| 567 | |
| 568 | *cp = init_chardata; |
| 569 | |
| 570 | /* Flush pending input (esp. after parsing or switching the baud rate). */ |
| 571 | |
| 572 | (void) sleep(1); |
| 573 | (void) ioctl(0, TCFLSH, TCIFLUSH); |
| 574 | |
| 575 | /* Prompt for and read a login name. */ |
| 576 | |
| 577 | for (*logname = 0; *logname == 0; /* void */ ) { |
| 578 | |
| 579 | /* Write issue file and prompt, with "parity" bit == 0. */ |
| 580 | |
| 581 | do_prompt(op, tp); |
| 582 | |
| 583 | /* Read name, watch for break, parity, erase, kill, end-of-line. */ |
| 584 | |
| 585 | for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) { |
| 586 | |
| 587 | /* Do not report trivial EINTR/EIO errors. */ |
| 588 | |
| 589 | if (read(0, &c, 1) < 1) { |
| 590 | if (errno == EINTR || errno == EIO) |
| 591 | exit(0); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 592 | bb_perror_msg_and_die("%s: read", op->tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 593 | } |
| 594 | /* Do BREAK handling elsewhere. */ |
| 595 | |
| 596 | if ((c == 0) && op->numspeed > 1) |
| 597 | /* return (0); */ |
| 598 | return NULL; |
| 599 | |
| 600 | /* Do parity bit handling. */ |
| 601 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 602 | if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 603 | for (bits = 1, mask = 1; mask & 0177; mask <<= 1) |
| 604 | if (mask & ascval) |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 605 | bits++; /* count "1" bits */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 606 | cp->parity |= ((bits & 1) ? 1 : 2); |
| 607 | } |
| 608 | /* Do erase, kill and end-of-line processing. */ |
| 609 | |
| 610 | switch (ascval) { |
| 611 | case CR: |
| 612 | case NL: |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 613 | *bp = 0; /* terminate logname */ |
| 614 | cp->eol = ascval; /* set end-of-line char */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 615 | break; |
| 616 | case BS: |
| 617 | case DEL: |
| 618 | case '#': |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 619 | cp->erase = ascval; /* set erase character */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 620 | if (bp > logname) { |
| 621 | (void) write(1, erase[cp->parity], 3); |
| 622 | bp--; |
| 623 | } |
| 624 | break; |
| 625 | case CTL('U'): |
| 626 | case '@': |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 627 | cp->kill = ascval; /* set kill character */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 628 | while (bp > logname) { |
| 629 | (void) write(1, erase[cp->parity], 3); |
| 630 | bp--; |
| 631 | } |
| 632 | break; |
| 633 | case CTL('D'): |
| 634 | exit(0); |
| 635 | default: |
| 636 | if (!isascii(ascval) || !isprint(ascval)) { |
| 637 | /* ignore garbage characters */ ; |
| 638 | } else if (bp - logname >= sizeof(logname) - 1) { |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 639 | bb_error_msg_and_die("%s: input overrun", op->tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 640 | } else { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 641 | (void) write(1, &c, 1); /* echo the character */ |
| 642 | *bp++ = ascval; /* and store it */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 643 | } |
| 644 | break; |
| 645 | } |
| 646 | } |
| 647 | } |
| 648 | /* Handle names with upper case and no lower case. */ |
| 649 | |
| 650 | if ((cp->capslock = caps_lock(logname))) { |
| 651 | for (bp = logname; *bp; bp++) |
| 652 | if (isupper(*bp)) |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 653 | *bp = tolower(*bp); /* map name to lower case */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 654 | } |
| 655 | return (logname); |
| 656 | } |
| 657 | |
| 658 | /* termio_final - set the final tty mode bits */ |
| 659 | static void termio_final(struct options *op, struct termio *tp, struct chardata *cp) |
| 660 | { |
| 661 | /* General terminal-independent stuff. */ |
| 662 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 663 | tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 664 | tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; |
| 665 | /* no longer| ECHOCTL | ECHOPRT */ |
| 666 | tp->c_oflag |= OPOST; |
| 667 | /* tp->c_cflag = 0; */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 668 | tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ |
| 669 | tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ |
| 670 | tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 671 | tp->c_cc[VEOL] = DEF_EOL; |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 672 | tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 673 | |
| 674 | /* Account for special characters seen in input. */ |
| 675 | |
| 676 | if (cp->eol == CR) { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 677 | tp->c_iflag |= ICRNL; /* map CR in input to NL */ |
| 678 | tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 679 | } |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 680 | tp->c_cc[VERASE] = cp->erase; /* set erase character */ |
| 681 | tp->c_cc[VKILL] = cp->kill; /* set kill character */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 682 | |
| 683 | /* Account for the presence or absence of parity bits in input. */ |
| 684 | |
| 685 | switch (cp->parity) { |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 686 | case 0: /* space (always 0) parity */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 687 | break; |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 688 | case 1: /* odd parity */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 689 | tp->c_cflag |= PARODD; |
| 690 | /* FALLTHROUGH */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 691 | case 2: /* even parity */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 692 | tp->c_cflag |= PARENB; |
| 693 | tp->c_iflag |= INPCK | ISTRIP; |
| 694 | /* FALLTHROUGH */ |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 695 | case (1 | 2): /* no parity bit */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 696 | tp->c_cflag &= ~CSIZE; |
| 697 | tp->c_cflag |= CS7; |
| 698 | break; |
| 699 | } |
| 700 | /* Account for upper case without lower case. */ |
| 701 | |
| 702 | if (cp->capslock) { |
| 703 | tp->c_iflag |= IUCLC; |
| 704 | tp->c_lflag |= XCASE; |
| 705 | tp->c_oflag |= OLCUC; |
| 706 | } |
| 707 | /* Optionally enable hardware flow control */ |
| 708 | |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 709 | #ifdef CRTSCTS |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 710 | if (op->flags & F_RTSCTS) |
| 711 | tp->c_cflag |= CRTSCTS; |
| 712 | #endif |
| 713 | |
| 714 | /* Finally, make the new settings effective */ |
| 715 | |
| 716 | if (ioctl(0, TCSETA, tp) < 0) |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 717 | bb_perror_msg_and_die("%s: ioctl(TCSETA)", op->tty); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 718 | } |
| 719 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 720 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 721 | #ifdef SYSV_STYLE |
| 722 | #ifdef CONFIG_FEATURE_UTMP |
| 723 | /* update_utmp - update our utmp entry */ |
| 724 | static void update_utmp(char *line) |
| 725 | { |
| 726 | struct utmp ut; |
| 727 | struct utmp *utp; |
| 728 | time_t t; |
| 729 | int mypid = getpid(); |
| 730 | #if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)) |
| 731 | struct flock lock; |
| 732 | #endif |
| 733 | |
| 734 | /* |
| 735 | * The utmp file holds miscellaneous information about things started by |
| 736 | * /sbin/init and other system-related events. Our purpose is to update |
| 737 | * the utmp entry for the current process, in particular the process type |
| 738 | * and the tty line we are listening to. Return successfully only if the |
| 739 | * utmp file can be opened for update, and if we are able to find our |
| 740 | * entry in the utmp file. |
| 741 | */ |
| 742 | if (access(_PATH_UTMP, R_OK|W_OK) == -1) { |
| 743 | close(creat(_PATH_UTMP, 0664)); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 744 | } |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 745 | utmpname(_PATH_UTMP); |
| 746 | setutent(); |
| 747 | while ((utp = getutent()) |
| 748 | && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */ |
| 749 | ; |
| 750 | |
| 751 | if (utp) { |
| 752 | memcpy(&ut, utp, sizeof(ut)); |
| 753 | } else { |
| 754 | /* some inits don't initialize utmp... */ |
| 755 | memset(&ut, 0, sizeof(ut)); |
Rob Landley | cf7577d | 2006-06-25 22:59:31 +0000 | [diff] [blame] | 756 | safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 757 | } |
| 758 | /*endutent(); */ |
| 759 | |
Rob Landley | cf7577d | 2006-06-25 22:59:31 +0000 | [diff] [blame] | 760 | strcpy(ut.ut_user, "LOGIN"); |
| 761 | safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line)); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 762 | if (fakehost) |
Rob Landley | cf7577d | 2006-06-25 22:59:31 +0000 | [diff] [blame] | 763 | safe_strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 764 | time(&t); |
| 765 | ut.ut_time = t; |
| 766 | ut.ut_type = LOGIN_PROCESS; |
| 767 | ut.ut_pid = mypid; |
| 768 | |
| 769 | pututline(&ut); |
| 770 | endutent(); |
| 771 | |
| 772 | #ifdef CONFIG_FEATURE_WTMP |
| 773 | if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) |
| 774 | close(creat(bb_path_wtmp_file, 0664)); |
| 775 | updwtmp(bb_path_wtmp_file, &ut); |
| 776 | #endif |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 777 | } |
| 778 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 779 | #endif /* CONFIG_FEATURE_UTMP */ |
| 780 | #endif /* SYSV_STYLE */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 781 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 782 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 783 | #undef logname |
| 784 | int getty_main(int argc, char **argv) |
| 785 | { |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 786 | int nullfd; |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 787 | char *logname = NULL; /* login name, given to /bin/login */ |
| 788 | struct chardata chardata; /* set by get_logname() */ |
| 789 | struct termio termio; /* terminal mode bits */ |
| 790 | static struct options options = { |
| 791 | 0, /* show /etc/issue (SYSV_STYLE) */ |
| 792 | 0, /* no timeout */ |
| 793 | _PATH_LOGIN, /* default login program */ |
| 794 | "tty1", /* default tty line */ |
| 795 | "", /* modem init string */ |
| 796 | #ifdef ISSUE |
| 797 | ISSUE, /* default issue file */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 798 | #else |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 799 | NULL, |
| 800 | #endif |
| 801 | 0, /* no baud rates known yet */ |
| 802 | }; |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 803 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 804 | /* Already too late because of theoretical |
| 805 | * possibility of getty --help somehow triggered |
| 806 | * inadvertently before we reach this. Oh well. */ |
| 807 | close(0); |
| 808 | close(1); |
| 809 | close(2); |
| 810 | #ifdef __linux__ |
| 811 | setsid(); |
| 812 | #endif |
| 813 | /* We want special flavor of error_msg_and_die */ |
Denis Vlasenko | 9213a9e | 2006-09-17 16:28:10 +0000 | [diff] [blame] | 814 | die_sleep = 10; |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 815 | msg_eol = "\r\n"; |
| 816 | /* Was "/dev/console". Why should we spam *system console* |
| 817 | * if there is a problem with getty on /dev/ttyS15?... */ |
Denis Vlasenko | 9213a9e | 2006-09-17 16:28:10 +0000 | [diff] [blame] | 818 | nullfd = xopen(bb_dev_null, O_RDWR); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 819 | dup2(nullfd, 0); |
| 820 | dup2(nullfd, 1); |
| 821 | dup2(nullfd, 2); |
| 822 | if(nullfd > 2) |
| 823 | close(nullfd); |
| 824 | openlog(bb_applet_name, LOG_PID, LOG_AUTH); |
| 825 | logmode = LOGMODE_BOTH; |
| 826 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 827 | #ifdef DEBUGGING |
Rob Landley | d921b2e | 2006-08-03 15:41:12 +0000 | [diff] [blame] | 828 | dbf = xfopen(DEBUGTERM, "w"); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 829 | |
| 830 | { |
| 831 | int i; |
| 832 | |
| 833 | for (i = 1; i < argc; i++) { |
| 834 | debug(argv[i]); |
| 835 | debug("\n"); |
| 836 | } |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 837 | } |
| 838 | #endif |
"Vladimir N. Oleynik" | 3e245c9 | 2005-09-29 11:31:26 +0000 | [diff] [blame] | 839 | |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 840 | /* Parse command-line arguments. */ |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 841 | parse_args(argc, argv, &options); |
| 842 | |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 843 | #ifdef SYSV_STYLE |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 844 | #ifdef CONFIG_FEATURE_UTMP |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 845 | /* Update the utmp file. */ |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 846 | update_utmp(options.tty); |
| 847 | #endif |
| 848 | #endif |
| 849 | |
| 850 | debug("calling open_tty\n"); |
| 851 | /* Open the tty as standard { input, output, error }. */ |
| 852 | open_tty(options.tty, &termio, options.flags & F_LOCAL); |
| 853 | |
| 854 | #ifdef __linux__ |
| 855 | { |
| 856 | int iv; |
| 857 | |
| 858 | iv = getpid(); |
| 859 | ioctl(0, TIOCSPGRP, &iv); |
| 860 | } |
| 861 | #endif |
| 862 | /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */ |
| 863 | debug("calling termio_init\n"); |
| 864 | termio_init(&termio, options.speeds[FIRST_SPEED], &options); |
| 865 | |
| 866 | /* write the modem init string and DON'T flush the buffers */ |
| 867 | if (options.flags & F_INITSTRING) { |
| 868 | debug("writing init string\n"); |
| 869 | write(1, options.initstring, strlen(options.initstring)); |
| 870 | } |
| 871 | |
| 872 | if (!(options.flags & F_LOCAL)) { |
| 873 | /* go to blocking write mode unless -L is specified */ |
| 874 | fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK); |
| 875 | } |
| 876 | |
| 877 | /* Optionally detect the baud rate from the modem status message. */ |
| 878 | debug("before autobaud\n"); |
| 879 | if (options.flags & F_PARSE) |
| 880 | auto_baud(&termio); |
| 881 | |
| 882 | /* Set the optional timer. */ |
| 883 | if (options.timeout) |
| 884 | (void) alarm((unsigned) options.timeout); |
| 885 | |
| 886 | /* optionally wait for CR or LF before writing /etc/issue */ |
| 887 | if (options.flags & F_WAITCRLF) { |
| 888 | char ch; |
| 889 | |
| 890 | debug("waiting for cr-lf\n"); |
| 891 | while (read(0, &ch, 1) == 1) { |
| 892 | ch &= 0x7f; /* strip "parity bit" */ |
| 893 | #ifdef DEBUGGING |
| 894 | fprintf(dbf, "read %c\n", ch); |
| 895 | #endif |
| 896 | if (ch == '\n' || ch == '\r') |
| 897 | break; |
| 898 | } |
| 899 | } |
| 900 | |
| 901 | chardata = init_chardata; |
| 902 | if (!(options.flags & F_NOPROMPT)) { |
| 903 | /* Read the login name. */ |
| 904 | debug("reading login name\n"); |
| 905 | /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */ |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 906 | logname = get_logname(&options, &chardata, &termio); |
| 907 | while (logname == NULL) |
| 908 | next_speed(&termio, &options); |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 909 | } |
| 910 | |
| 911 | /* Disable timer. */ |
| 912 | |
| 913 | if (options.timeout) |
| 914 | (void) alarm(0); |
| 915 | |
| 916 | /* Finalize the termio settings. */ |
| 917 | |
| 918 | termio_final(&options, &termio, &chardata); |
| 919 | |
| 920 | /* Now the newline character should be properly written. */ |
| 921 | |
| 922 | (void) write(1, "\n", 1); |
| 923 | |
| 924 | /* Let the login program take care of password validation. */ |
| 925 | |
| 926 | (void) execl(options.login, options.login, "--", logname, (char *) 0); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 927 | bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 928 | } |
Bernhard Reutner-Fischer | 6d82f94 | 2006-06-16 16:37:07 +0000 | [diff] [blame] | 929 | |