diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-01-24 04:43:04 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-01-24 04:43:04 +0100 |
commit | 6596380f52cd48b8b44443bb5677ec8caf538761 (patch) | |
tree | 0628643e7f1230fc4fa7b6448231fe1378673022 | |
parent | e9a40e3b91f699c08053d7307bf50b0764811b8e (diff) | |
download | busybox-w32-6596380f52cd48b8b44443bb5677ec8caf538761.tar.gz busybox-w32-6596380f52cd48b8b44443bb5677ec8caf538761.tar.bz2 busybox-w32-6596380f52cd48b8b44443bb5677ec8caf538761.zip |
getty: simplify code by going to more straignforward G trick
function old new delta
getty_main 1615 1475 -140
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | loginutils/getty.c | 396 |
1 files changed, 121 insertions, 275 deletions
diff --git a/loginutils/getty.c b/loginutils/getty.c index 13b341db5..bf66f2287 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c | |||
@@ -16,11 +16,9 @@ | |||
16 | 16 | ||
17 | #include "libbb.h" | 17 | #include "libbb.h" |
18 | #include <syslog.h> | 18 | #include <syslog.h> |
19 | |||
20 | #if ENABLE_FEATURE_UTMP | 19 | #if ENABLE_FEATURE_UTMP |
21 | # include <utmp.h> /* LOGIN_PROCESS */ | 20 | # include <utmp.h> /* LOGIN_PROCESS */ |
22 | #endif | 21 | #endif |
23 | |||
24 | #ifndef IUCLC | 22 | #ifndef IUCLC |
25 | # define IUCLC 0 | 23 | # define IUCLC 0 |
26 | #endif | 24 | #endif |
@@ -36,7 +34,7 @@ | |||
36 | # undef ENABLE_FEATURE_WTMP | 34 | # undef ENABLE_FEATURE_WTMP |
37 | # define ENABLE_FEATURE_UTMP 0 | 35 | # define ENABLE_FEATURE_UTMP 0 |
38 | # define ENABLE_FEATURE_WTMP 0 | 36 | # define ENABLE_FEATURE_WTMP 0 |
39 | #endif /* LOGIN_PROCESS */ | 37 | #endif |
40 | 38 | ||
41 | 39 | ||
42 | /* The following is used for understandable diagnostics. */ | 40 | /* The following is used for understandable diagnostics. */ |
@@ -56,18 +54,6 @@ static FILE *dbf; | |||
56 | * below. Note, however, that DEL cannot be used for interrupt generation | 54 | * below. Note, however, that DEL cannot be used for interrupt generation |
57 | * and for line editing at the same time. | 55 | * and for line editing at the same time. |
58 | */ | 56 | */ |
59 | |||
60 | /* I doubt there are systems which still... */ | ||
61 | /* ...have only uppercase: */ | ||
62 | #undef HANDLE_ALLCAPS | ||
63 | /* ...use # and @ for backspace and line erase: */ | ||
64 | #undef ANCIENT_BS_KILL_CHARS | ||
65 | /* It actually makes sense (tries to guess parity by looking at 7th bit) | ||
66 | * but it's broken, and interferes with non-ASCII login names | ||
67 | * (yes, I did receive complains from real users): | ||
68 | */ | ||
69 | #undef BROKEN_PARITY_DETECTION_CODE | ||
70 | |||
71 | #undef _PATH_LOGIN | 57 | #undef _PATH_LOGIN |
72 | #define _PATH_LOGIN "/bin/login" | 58 | #define _PATH_LOGIN "/bin/login" |
73 | 59 | ||
@@ -100,8 +86,7 @@ static FILE *dbf; | |||
100 | */ | 86 | */ |
101 | #define MAX_SPEED 10 /* max. nr. of baud rates */ | 87 | #define MAX_SPEED 10 /* max. nr. of baud rates */ |
102 | 88 | ||
103 | /* Storage for command-line options. */ | 89 | struct globals { |
104 | struct options { | ||
105 | unsigned timeout; /* time-out period */ | 90 | unsigned timeout; /* time-out period */ |
106 | const char *login; /* login program */ | 91 | const char *login; /* login program */ |
107 | const char *tty; /* name of tty */ | 92 | const char *tty; /* name of tty */ |
@@ -109,46 +94,17 @@ struct options { | |||
109 | const char *issue; /* alternative issue file */ | 94 | const char *issue; /* alternative issue file */ |
110 | int numspeed; /* number of baud rates to try */ | 95 | int numspeed; /* number of baud rates to try */ |
111 | int speeds[MAX_SPEED]; /* baud rates to be tried */ | 96 | int speeds[MAX_SPEED]; /* baud rates to be tried */ |
97 | struct termios termios; /* terminal mode bits */ | ||
98 | /* Storage for things detected while the login name was read. */ | ||
99 | unsigned char erase; /* erase character */ | ||
100 | unsigned char eol; /* end-of-line character */ | ||
101 | char line_buf[128]; | ||
112 | }; | 102 | }; |
113 | 103 | ||
114 | /* Storage for things detected while the login name was read. */ | 104 | #define G (*ptr_to_globals) |
115 | struct chardata { | 105 | #define INIT_G() do { \ |
116 | unsigned char erase; /* erase character */ | 106 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
117 | #ifdef ANCIENT_BS_KILL_CHARS | 107 | } while (0) |
118 | unsigned char kill; /* kill character */ | ||
119 | #endif | ||
120 | unsigned char eol; /* end-of-line character */ | ||
121 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
122 | unsigned char parity; /* what parity did we see */ | ||
123 | /* (parity & 1): saw odd parity char with 7th bit set */ | ||
124 | /* (parity & 2): saw even parity char with 7th bit set */ | ||
125 | /* parity == 0: probably 7-bit, space parity? */ | ||
126 | /* parity == 1: probably 7-bit, odd parity? */ | ||
127 | /* parity == 2: probably 7-bit, even parity? */ | ||
128 | /* parity == 3: definitely 8 bit, no parity! */ | ||
129 | /* Hmm... with any value of parity "8 bit, no parity" is possible */ | ||
130 | #endif | ||
131 | #ifdef HANDLE_ALLCAPS | ||
132 | unsigned char capslock; /* upper case without lower case */ | ||
133 | #endif | ||
134 | }; | ||
135 | |||
136 | /* Initial values for the above. */ | ||
137 | static const struct chardata init_chardata = { | ||
138 | DEF_ERASE, /* default erase character */ | ||
139 | #ifdef ANCIENT_BS_KILL_CHARS | ||
140 | DEF_KILL, /* default kill character */ | ||
141 | #endif | ||
142 | 13, /* default eol char */ | ||
143 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
144 | 0, /* space parity */ | ||
145 | #endif | ||
146 | #ifdef HANDLE_ALLCAPS | ||
147 | 0, /* no capslock */ | ||
148 | #endif | ||
149 | }; | ||
150 | |||
151 | #define line_buf bb_common_bufsiz1 | ||
152 | 108 | ||
153 | //usage:#define getty_trivial_usage | 109 | //usage:#define getty_trivial_usage |
154 | //usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]" | 110 | //usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]" |
@@ -193,52 +149,53 @@ static int bcode(const char *s) | |||
193 | } | 149 | } |
194 | 150 | ||
195 | /* parse alternate baud rates */ | 151 | /* parse alternate baud rates */ |
196 | static void parse_speeds(struct options *op, char *arg) | 152 | static void parse_speeds(char *arg) |
197 | { | 153 | { |
198 | char *cp; | 154 | char *cp; |
199 | 155 | ||
200 | /* NB: at least one iteration is always done */ | 156 | /* NB: at least one iteration is always done */ |
201 | debug("entered parse_speeds\n"); | 157 | debug("entered parse_speeds\n"); |
202 | while ((cp = strsep(&arg, ",")) != NULL) { | 158 | while ((cp = strsep(&arg, ",")) != NULL) { |
203 | op->speeds[op->numspeed] = bcode(cp); | 159 | G.speeds[G.numspeed] = bcode(cp); |
204 | if (op->speeds[op->numspeed] < 0) | 160 | if (G.speeds[G.numspeed] < 0) |
205 | bb_error_msg_and_die("bad speed: %s", cp); | 161 | bb_error_msg_and_die("bad speed: %s", cp); |
206 | /* note: arg "0" turns into speed B0 */ | 162 | /* note: arg "0" turns into speed B0 */ |
207 | op->numspeed++; | 163 | G.numspeed++; |
208 | if (op->numspeed > MAX_SPEED) | 164 | if (G.numspeed > MAX_SPEED) |
209 | bb_error_msg_and_die("too many alternate speeds"); | 165 | bb_error_msg_and_die("too many alternate speeds"); |
210 | } | 166 | } |
211 | debug("exiting parse_speeds\n"); | 167 | debug("exiting parse_speeds\n"); |
212 | } | 168 | } |
213 | 169 | ||
214 | /* parse command-line arguments */ | 170 | /* parse command-line arguments */ |
215 | static void parse_args(char **argv, struct options *op, char **fakehost_p) | 171 | static void parse_args(char **argv, char **fakehost_p) |
216 | { | 172 | { |
217 | char *ts; | 173 | char *ts; |
218 | int flags; | 174 | int flags; |
219 | 175 | ||
220 | opt_complementary = "-2:t+"; /* at least 2 args; -t N */ | 176 | opt_complementary = "-2:t+"; /* at least 2 args; -t N */ |
221 | flags = getopt32(argv, opt_string, | 177 | flags = getopt32(argv, opt_string, |
222 | &(op->initstring), fakehost_p, &(op->issue), | 178 | &G.initstring, fakehost_p, &G.issue, |
223 | &(op->login), &op->timeout); | 179 | &G.login, &G.timeout |
180 | ); | ||
224 | if (flags & F_INITSTRING) { | 181 | if (flags & F_INITSTRING) { |
225 | op->initstring = xstrdup(op->initstring); | 182 | G.initstring = xstrdup(G.initstring); |
226 | /* decode \ddd octal codes into chars */ | 183 | /* decode \ddd octal codes into chars */ |
227 | strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring); | 184 | strcpy_and_process_escape_sequences((char*)G.initstring, G.initstring); |
228 | } | 185 | } |
229 | argv += optind; | 186 | argv += optind; |
230 | debug("after getopt\n"); | 187 | debug("after getopt\n"); |
231 | 188 | ||
232 | /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ | 189 | /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ |
233 | op->tty = argv[0]; /* tty name */ | 190 | G.tty = argv[0]; /* tty name */ |
234 | ts = argv[1]; /* baud rate(s) */ | 191 | ts = argv[1]; /* baud rate(s) */ |
235 | if (isdigit(argv[0][0])) { | 192 | if (isdigit(argv[0][0])) { |
236 | /* a number first, assume it's a speed (BSD style) */ | 193 | /* A number first, assume it's a speed (BSD style) */ |
237 | op->tty = ts; /* tty name is in argv[1] */ | 194 | G.tty = ts; /* tty name is in argv[1] */ |
238 | ts = argv[0]; /* baud rate(s) */ | 195 | ts = argv[0]; /* baud rate(s) */ |
239 | } | 196 | } |
240 | parse_speeds(op, ts); | 197 | parse_speeds(ts); |
241 | applet_name = xasprintf("getty: %s", op->tty); | 198 | applet_name = xasprintf("getty: %s", G.tty); |
242 | 199 | ||
243 | if (argv[2]) | 200 | if (argv[2]) |
244 | xsetenv("TERM", argv[2]); | 201 | xsetenv("TERM", argv[2]); |
@@ -247,17 +204,17 @@ static void parse_args(char **argv, struct options *op, char **fakehost_p) | |||
247 | } | 204 | } |
248 | 205 | ||
249 | /* set up tty as standard input, output, error */ | 206 | /* set up tty as standard input, output, error */ |
250 | static void open_tty(const char *tty) | 207 | static void open_tty(void) |
251 | { | 208 | { |
252 | /* Set up new standard input, unless we are given an already opened port. */ | 209 | /* Set up new standard input, unless we are given an already opened port. */ |
253 | if (NOT_LONE_DASH(tty)) { | 210 | if (NOT_LONE_DASH(G.tty)) { |
254 | if (tty[0] != '/') | 211 | if (G.tty[0] != '/') |
255 | tty = xasprintf("/dev/%s", tty); /* will leak it */ | 212 | G.tty = xasprintf("/dev/%s", G.tty); /* will leak it */ |
256 | 213 | ||
257 | /* Open the tty as standard input. */ | 214 | /* Open the tty as standard input. */ |
258 | debug("open(2)\n"); | 215 | debug("open(2)\n"); |
259 | close(0); | 216 | close(0); |
260 | /*fd =*/ xopen(tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ | 217 | xopen(G.tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ |
261 | 218 | ||
262 | /* Set proper protections and ownership. */ | 219 | /* Set proper protections and ownership. */ |
263 | fchown(0, 0, 0); /* 0:0 */ | 220 | fchown(0, 0, 0); /* 0:0 */ |
@@ -273,7 +230,7 @@ static void open_tty(const char *tty) | |||
273 | } | 230 | } |
274 | 231 | ||
275 | /* initialize termios settings */ | 232 | /* initialize termios settings */ |
276 | static void termios_init(struct termios *tp, int speed) | 233 | static void termios_init(int speed) |
277 | { | 234 | { |
278 | /* Flush input and output queues, important for modems! | 235 | /* Flush input and output queues, important for modems! |
279 | * Users report losing previously queued output chars, and I hesitate | 236 | * Users report losing previously queued output chars, and I hesitate |
@@ -285,7 +242,7 @@ static void termios_init(struct termios *tp, int speed) | |||
285 | 242 | ||
286 | /* Set speed if it wasn't specified as "0" on command line. */ | 243 | /* Set speed if it wasn't specified as "0" on command line. */ |
287 | if (speed != B0) | 244 | if (speed != B0) |
288 | cfsetspeed(tp, speed); | 245 | cfsetspeed(&G.termios, speed); |
289 | 246 | ||
290 | /* | 247 | /* |
291 | * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. | 248 | * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. |
@@ -293,31 +250,29 @@ static void termios_init(struct termios *tp, int speed) | |||
293 | * reads will be done in raw mode anyway. Errors will be dealt with | 250 | * reads will be done in raw mode anyway. Errors will be dealt with |
294 | * later on. | 251 | * later on. |
295 | */ | 252 | */ |
296 | tp->c_cflag = CS8 | HUPCL | CREAD; | 253 | G.termios.c_cflag = CS8 | HUPCL | CREAD; |
297 | if (option_mask32 & F_LOCAL) | 254 | if (option_mask32 & F_LOCAL) |
298 | tp->c_cflag |= CLOCAL; | 255 | G.termios.c_cflag |= CLOCAL; |
299 | tp->c_iflag = 0; | 256 | G.termios.c_iflag = 0; |
300 | tp->c_lflag = 0; | 257 | G.termios.c_lflag = 0; |
301 | tp->c_oflag = OPOST | ONLCR; | 258 | G.termios.c_oflag = OPOST | ONLCR; |
302 | tp->c_cc[VMIN] = 1; | 259 | G.termios.c_cc[VMIN] = 1; |
303 | tp->c_cc[VTIME] = 0; | 260 | G.termios.c_cc[VTIME] = 0; |
304 | #ifdef __linux__ | 261 | #ifdef __linux__ |
305 | tp->c_line = 0; | 262 | G.termios.c_line = 0; |
306 | #endif | 263 | #endif |
307 | |||
308 | /* Optionally enable hardware flow control */ | ||
309 | #ifdef CRTSCTS | 264 | #ifdef CRTSCTS |
310 | if (option_mask32 & F_RTSCTS) | 265 | if (option_mask32 & F_RTSCTS) |
311 | tp->c_cflag |= CRTSCTS; | 266 | G.termios.c_cflag |= CRTSCTS; |
312 | #endif | 267 | #endif |
313 | 268 | ||
314 | tcsetattr_stdin_TCSANOW(tp); | 269 | tcsetattr_stdin_TCSANOW(&G.termios); |
315 | 270 | ||
316 | debug("term_io 2\n"); | 271 | debug("term_io 2\n"); |
317 | } | 272 | } |
318 | 273 | ||
319 | /* extract baud rate from modem status message */ | 274 | /* extract baud rate from modem status message */ |
320 | static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) | 275 | static void auto_baud(void) |
321 | { | 276 | { |
322 | int speed; | 277 | int speed; |
323 | int vmin; | 278 | int vmin; |
@@ -344,83 +299,60 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) | |||
344 | * Use 7-bit characters, don't block if input queue is empty. Errors will | 299 | * Use 7-bit characters, don't block if input queue is empty. Errors will |
345 | * be dealt with later on. | 300 | * be dealt with later on. |
346 | */ | 301 | */ |
347 | iflag = tp->c_iflag; | 302 | iflag = G.termios.c_iflag; |
348 | tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ | 303 | G.termios.c_iflag |= ISTRIP; /* enable 8th-bit stripping */ |
349 | vmin = tp->c_cc[VMIN]; | 304 | vmin = G.termios.c_cc[VMIN]; |
350 | tp->c_cc[VMIN] = 0; /* don't block if queue empty */ | 305 | G.termios.c_cc[VMIN] = 0; /* don't block if queue empty */ |
351 | tcsetattr_stdin_TCSANOW(tp); | 306 | tcsetattr_stdin_TCSANOW(&G.termios); |
352 | 307 | ||
353 | /* | 308 | /* |
354 | * Wait for a while, then read everything the modem has said so far and | 309 | * Wait for a while, then read everything the modem has said so far and |
355 | * try to extract the speed of the dial-in call. | 310 | * try to extract the speed of the dial-in call. |
356 | */ | 311 | */ |
357 | sleep(1); | 312 | sleep(1); |
358 | nread = safe_read(STDIN_FILENO, buf, size_buf - 1); | 313 | nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1); |
359 | if (nread > 0) { | 314 | if (nread > 0) { |
360 | buf[nread] = '\0'; | 315 | G.line_buf[nread] = '\0'; |
361 | for (bp = buf; bp < buf + nread; bp++) { | 316 | for (bp = G.line_buf; bp < G.line_buf + nread; bp++) { |
362 | if (isdigit(*bp)) { | 317 | if (isdigit(*bp)) { |
363 | speed = bcode(bp); | 318 | speed = bcode(bp); |
364 | if (speed > 0) | 319 | if (speed > 0) |
365 | cfsetspeed(tp, speed); | 320 | cfsetspeed(&G.termios, speed); |
366 | break; | 321 | break; |
367 | } | 322 | } |
368 | } | 323 | } |
369 | } | 324 | } |
370 | 325 | ||
371 | /* Restore terminal settings. Errors will be dealt with later on. */ | 326 | /* Restore terminal settings. Errors will be dealt with later on. */ |
372 | tp->c_iflag = iflag; | 327 | G.termios.c_iflag = iflag; |
373 | tp->c_cc[VMIN] = vmin; | 328 | G.termios.c_cc[VMIN] = vmin; |
374 | tcsetattr_stdin_TCSANOW(tp); | 329 | tcsetattr_stdin_TCSANOW(&G.termios); |
375 | } | ||
376 | |||
377 | #ifdef HANDLE_ALLCAPS | ||
378 | /* does string contain upper case without lower case? */ | ||
379 | static int all_is_upcase(const char *s) | ||
380 | { | ||
381 | while (*s) | ||
382 | if (islower(*s++)) | ||
383 | return 0; | ||
384 | return 1; | ||
385 | } | 330 | } |
386 | #endif | ||
387 | 331 | ||
388 | /* get user name, establish parity, speed, erase, kill, eol; | 332 | /* get user name, establish parity, speed, erase, kill, eol; |
389 | * return NULL on BREAK, logname on success */ | 333 | * return NULL on BREAK, logname on success */ |
390 | static char *get_logname(char *logname, unsigned size_logname, | 334 | static char *get_logname(void) |
391 | struct options *op, struct chardata *cp) | ||
392 | { | 335 | { |
393 | char *bp; | 336 | char *bp; |
394 | char c; /* input character, full eight bits */ | 337 | char c; |
395 | char ascval; /* low 7 bits of input character */ | ||
396 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
397 | static const char erase[][3] = {/* backspace-space-backspace */ | ||
398 | "\010\040\010", /* space parity */ | ||
399 | "\010\040\010", /* odd parity */ | ||
400 | "\210\240\210", /* even parity */ | ||
401 | "\010\040\010", /* 8 bit no parity */ | ||
402 | }; | ||
403 | #endif | ||
404 | |||
405 | /* NB: *cp is pre-initialized with init_chardata */ | ||
406 | 338 | ||
407 | /* Flush pending input (esp. after parsing or switching the baud rate). */ | 339 | /* Flush pending input (esp. after parsing or switching the baud rate). */ |
408 | usleep(100*1000); /* 0.1 sec */ | 340 | usleep(100*1000); /* 0.1 sec */ |
409 | tcflush(STDIN_FILENO, TCIOFLUSH); | 341 | tcflush(STDIN_FILENO, TCIOFLUSH); |
410 | 342 | ||
411 | /* Prompt for and read a login name. */ | 343 | /* Prompt for and read a login name. */ |
412 | logname[0] = '\0'; | 344 | G.line_buf[0] = '\0'; |
413 | while (!logname[0]) { | 345 | while (!G.line_buf[0]) { |
414 | /* Write issue file and prompt. */ | 346 | /* Write issue file and prompt. */ |
415 | #ifdef ISSUE | 347 | #ifdef ISSUE |
416 | if (!(option_mask32 & F_NOISSUE)) | 348 | if (!(option_mask32 & F_NOISSUE)) |
417 | print_login_issue(op->issue, op->tty); | 349 | print_login_issue(G.issue, G.tty); |
418 | #endif | 350 | #endif |
419 | print_login_prompt(); | 351 | print_login_prompt(); |
420 | 352 | ||
421 | /* Read name, watch for break, parity, erase, kill, end-of-line. */ | 353 | /* Read name, watch for break, parity, erase, kill, end-of-line. */ |
422 | bp = logname; | 354 | bp = G.line_buf; |
423 | cp->eol = '\0'; | 355 | G.eol = '\0'; |
424 | while (1) { | 356 | while (1) { |
425 | /* Do not report trivial EINTR/EIO errors. */ | 357 | /* Do not report trivial EINTR/EIO errors. */ |
426 | errno = EINTR; /* make read of 0 bytes be silent too */ | 358 | errno = EINTR; /* make read of 0 bytes be silent too */ |
@@ -432,71 +364,39 @@ static char *get_logname(char *logname, unsigned size_logname, | |||
432 | 364 | ||
433 | /* BREAK. If we have speeds to try, | 365 | /* BREAK. If we have speeds to try, |
434 | * return NULL (will switch speeds and return here) */ | 366 | * return NULL (will switch speeds and return here) */ |
435 | if (c == '\0' && op->numspeed > 1) | 367 | if (c == '\0' && G.numspeed > 1) |
436 | return NULL; | 368 | return NULL; |
437 | 369 | ||
438 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
439 | /* Do parity bit handling. */ | ||
440 | if (!(option_mask32 & F_LOCAL) && (c & 0x80)) { /* "parity" bit on? */ | ||
441 | int bits = 1; | ||
442 | int mask = 1; | ||
443 | while (mask & 0x7f) { | ||
444 | if (mask & c) | ||
445 | bits++; /* count "1" bits */ | ||
446 | mask <<= 1; | ||
447 | } | ||
448 | /* ... |= 2 - even, 1 - odd */ | ||
449 | cp->parity |= 2 - (bits & 1); | ||
450 | } | ||
451 | ascval = c & 0x7f; | ||
452 | #else | ||
453 | ascval = c; | ||
454 | #endif | ||
455 | |||
456 | /* Do erase, kill and end-of-line processing. */ | 370 | /* Do erase, kill and end-of-line processing. */ |
457 | switch (ascval) { | 371 | switch (c) { |
458 | case CR: | 372 | case CR: |
459 | case NL: | 373 | case NL: |
460 | *bp = '\0'; /* terminate logname */ | 374 | *bp = '\0'; |
461 | cp->eol = ascval; /* set end-of-line char */ | 375 | G.eol = c; |
462 | goto got_logname; | 376 | goto got_logname; |
463 | case BS: | 377 | case BS: |
464 | case DEL: | 378 | case DEL: |
465 | #ifdef ANCIENT_BS_KILL_CHARS | 379 | G.erase = c; |
466 | case '#': | 380 | if (bp > G.line_buf) { |
467 | #endif | ||
468 | cp->erase = ascval; /* set erase character */ | ||
469 | if (bp > logname) { | ||
470 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
471 | full_write(STDOUT_FILENO, erase[cp->parity], 3); | ||
472 | #else | ||
473 | full_write(STDOUT_FILENO, "\010 \010", 3); | 381 | full_write(STDOUT_FILENO, "\010 \010", 3); |
474 | #endif | ||
475 | bp--; | 382 | bp--; |
476 | } | 383 | } |
477 | break; | 384 | break; |
478 | case CTL('U'): | 385 | case CTL('U'): |
479 | #ifdef ANCIENT_BS_KILL_CHARS | 386 | while (bp > G.line_buf) { |
480 | case '@': | ||
481 | cp->kill = ascval; /* set kill character */ | ||
482 | #endif | ||
483 | while (bp > logname) { | ||
484 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
485 | full_write(STDOUT_FILENO, erase[cp->parity], 3); | ||
486 | #else | ||
487 | full_write(STDOUT_FILENO, "\010 \010", 3); | 387 | full_write(STDOUT_FILENO, "\010 \010", 3); |
488 | #endif | ||
489 | bp--; | 388 | bp--; |
490 | } | 389 | } |
491 | break; | 390 | break; |
492 | case CTL('D'): | 391 | case CTL('D'): |
493 | exit(EXIT_SUCCESS); | 392 | exit(EXIT_SUCCESS); |
494 | default: | 393 | default: |
495 | if (ascval < ' ') { | 394 | if ((unsigned char)c < ' ') { |
496 | /* ignore garbage characters */ | 395 | /* ignore garbage characters */ |
497 | } else if ((int)(bp - logname) < size_logname - 1) { | 396 | } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) { |
498 | full_write(STDOUT_FILENO, &c, 1); /* echo the character */ | 397 | /* echo and store the character */ |
499 | *bp++ = ascval; /* and store it */ | 398 | full_write(STDOUT_FILENO, &c, 1); |
399 | *bp++ = c; | ||
500 | } | 400 | } |
501 | break; | 401 | break; |
502 | } | 402 | } |
@@ -504,87 +404,42 @@ static char *get_logname(char *logname, unsigned size_logname, | |||
504 | got_logname: ; | 404 | got_logname: ; |
505 | } /* while logname is empty */ | 405 | } /* while logname is empty */ |
506 | 406 | ||
507 | #ifdef HANDLE_ALLCAPS | 407 | return G.line_buf; |
508 | /* Handle names with upper case and no lower case. */ | ||
509 | cp->capslock = all_is_upcase(logname); | ||
510 | if (cp->capslock) { | ||
511 | for (bp = logname; *bp; bp++) | ||
512 | if (isupper(*bp)) | ||
513 | *bp = tolower(*bp); /* map name to lower case */ | ||
514 | } | ||
515 | #endif | ||
516 | return logname; | ||
517 | } | 408 | } |
518 | 409 | ||
519 | /* set the final tty mode bits */ | 410 | /* set the final tty mode bits */ |
520 | static void termios_final(struct termios *tp, struct chardata *cp) | 411 | static void termios_final(void) |
521 | { | 412 | { |
522 | /* General terminal-independent stuff. */ | 413 | /* General terminal-independent stuff. */ |
523 | tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ | 414 | G.termios.c_iflag |= IXON | IXOFF; /* 2-way flow control */ |
524 | tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; | 415 | G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; |
525 | /* no longer| ECHOCTL | ECHOPRT */ | 416 | /* no longer in lflag: | ECHOCTL | ECHOPRT */ |
526 | tp->c_oflag |= OPOST; | 417 | G.termios.c_oflag |= OPOST; |
527 | /* tp->c_cflag = 0; */ | 418 | /* G.termios.c_cflag = 0; */ |
528 | tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ | 419 | G.termios.c_cc[VINTR] = DEF_INTR; /* default interrupt */ |
529 | tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ | 420 | G.termios.c_cc[VQUIT] = DEF_QUIT; /* default quit */ |
530 | tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ | 421 | G.termios.c_cc[VEOF] = DEF_EOF; /* default EOF character */ |
531 | tp->c_cc[VEOL] = DEF_EOL; | 422 | G.termios.c_cc[VEOL] = DEF_EOL; |
532 | #ifdef VSWTC | 423 | #ifdef VSWTC |
533 | tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ | 424 | G.termios.c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ |
534 | #endif | 425 | #endif |
535 | 426 | ||
536 | /* Account for special characters seen in input. */ | 427 | /* Account for special characters seen in input. */ |
537 | if (cp->eol == CR) { | 428 | if (G.eol == CR) { |
538 | tp->c_iflag |= ICRNL; /* map CR in input to NL */ | 429 | G.termios.c_iflag |= ICRNL; /* map CR in input to NL */ |
539 | tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ | 430 | G.termios.c_oflag |= ONLCR; /* map NL in output to CR-NL */ |
540 | } | ||
541 | tp->c_cc[VERASE] = cp->erase; /* set erase character */ | ||
542 | #ifdef ANCIENT_BS_KILL_CHARS | ||
543 | tp->c_cc[VKILL] = cp->kill; /* set kill character */ | ||
544 | #else | ||
545 | tp->c_cc[VKILL] = DEF_KILL; /* set kill character */ | ||
546 | #endif | ||
547 | |||
548 | #ifdef BROKEN_PARITY_DETECTION_CODE | ||
549 | /* Account for the presence or absence of parity bits in input. */ | ||
550 | switch (cp->parity) { | ||
551 | case 0: /* space (always 0) parity */ | ||
552 | // I bet most people go here - they use only 7-bit chars in usernames.... | ||
553 | break; | ||
554 | case 1: /* odd parity */ | ||
555 | tp->c_cflag |= PARODD; | ||
556 | /* FALLTHROUGH */ | ||
557 | case 2: /* even parity */ | ||
558 | tp->c_cflag |= PARENB; | ||
559 | tp->c_iflag |= INPCK | ISTRIP; | ||
560 | /* FALLTHROUGH */ | ||
561 | case (1 | 2): /* no parity bit */ | ||
562 | tp->c_cflag &= ~CSIZE; | ||
563 | tp->c_cflag |= CS7; | ||
564 | // FIXME: wtf? case 3: we saw both even and odd 8-bit bytes - | ||
565 | // it's probably some umlauts etc, but definitely NOT 7-bit!!! | ||
566 | // Entire parity detection madness here just begs for deletion... | ||
567 | break; | ||
568 | } | 431 | } |
569 | #endif | 432 | G.termios.c_cc[VERASE] = G.erase; /* set erase character */ |
570 | 433 | G.termios.c_cc[VKILL] = DEF_KILL; /* set kill character */ | |
571 | #ifdef HANDLE_ALLCAPS | ||
572 | /* Account for upper case without lower case. */ | ||
573 | if (cp->capslock) { | ||
574 | tp->c_iflag |= IUCLC; | ||
575 | tp->c_lflag |= XCASE; | ||
576 | tp->c_oflag |= OLCUC; | ||
577 | } | ||
578 | #endif | ||
579 | 434 | ||
580 | #ifdef CRTSCTS | 435 | #ifdef CRTSCTS |
581 | /* Optionally enable hardware flow control */ | 436 | /* Optionally enable hardware flow control */ |
582 | if (option_mask32 & F_RTSCTS) | 437 | if (option_mask32 & F_RTSCTS) |
583 | tp->c_cflag |= CRTSCTS; | 438 | G.termios.c_cflag |= CRTSCTS; |
584 | #endif | 439 | #endif |
585 | 440 | ||
586 | /* Finally, make the new settings effective */ | 441 | /* Finally, make the new settings effective */ |
587 | if (tcsetattr_stdin_TCSANOW(tp) < 0) | 442 | if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) |
588 | bb_perror_msg_and_die("tcsetattr"); | 443 | bb_perror_msg_and_die("tcsetattr"); |
589 | } | 444 | } |
590 | 445 | ||
@@ -593,27 +448,20 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
593 | { | 448 | { |
594 | int n; | 449 | int n; |
595 | pid_t pid; | 450 | pid_t pid; |
596 | char *fakehost = NULL; /* Fake hostname for ut_host */ | 451 | char *fakehost = NULL; /* Fake hostname for ut_host */ |
597 | char *logname; /* login name, given to /bin/login */ | 452 | char *logname; |
598 | /* Merging these into "struct local" may _seem_ to reduce | ||
599 | * parameter passing, but today's gcc will inline | ||
600 | * statics which are called once anyway, so don't do that */ | ||
601 | struct chardata chardata; /* set by get_logname() */ | ||
602 | struct termios termios; /* terminal mode bits */ | ||
603 | struct options options; | ||
604 | |||
605 | chardata = init_chardata; | ||
606 | 453 | ||
607 | memset(&options, 0, sizeof(options)); | 454 | INIT_G(); |
608 | options.login = _PATH_LOGIN; /* default login program */ | 455 | G.login = _PATH_LOGIN; /* default login program */ |
609 | options.tty = "tty1"; /* default tty line */ | 456 | G.initstring = ""; /* modem init string */ |
610 | options.initstring = ""; /* modem init string */ | ||
611 | #ifdef ISSUE | 457 | #ifdef ISSUE |
612 | options.issue = ISSUE; /* default issue file */ | 458 | G.issue = ISSUE; /* default issue file */ |
613 | #endif | 459 | #endif |
460 | G.erase = DEF_ERASE; | ||
461 | G.eol = CR; | ||
614 | 462 | ||
615 | /* Parse command-line arguments. */ | 463 | /* Parse command-line arguments. */ |
616 | parse_args(argv, &options, &fakehost); | 464 | parse_args(argv, &fakehost); |
617 | 465 | ||
618 | logmode = LOGMODE_NONE; | 466 | logmode = LOGMODE_NONE; |
619 | 467 | ||
@@ -648,7 +496,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
648 | /* Open the tty as standard input, if it is not "-" */ | 496 | /* Open the tty as standard input, if it is not "-" */ |
649 | /* If it's not "-" and not taken yet, it will become our ctty */ | 497 | /* If it's not "-" and not taken yet, it will become our ctty */ |
650 | debug("calling open_tty\n"); | 498 | debug("calling open_tty\n"); |
651 | open_tty(options.tty); | 499 | open_tty(); |
652 | ndelay_off(0); | 500 | ndelay_off(0); |
653 | debug("duping\n"); | 501 | debug("duping\n"); |
654 | xdup2(0, 1); | 502 | xdup2(0, 1); |
@@ -662,7 +510,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
662 | * by patching the SunOS kernel variable "zsadtrlow" to a larger value; | 510 | * by patching the SunOS kernel variable "zsadtrlow" to a larger value; |
663 | * 5 seconds seems to be a good value. | 511 | * 5 seconds seems to be a good value. |
664 | */ | 512 | */ |
665 | if (tcgetattr(STDIN_FILENO, &termios) < 0) | 513 | if (tcgetattr(STDIN_FILENO, &G.termios) < 0) |
666 | bb_perror_msg_and_die("tcgetattr"); | 514 | bb_perror_msg_and_die("tcgetattr"); |
667 | 515 | ||
668 | pid = getpid(); | 516 | pid = getpid(); |
@@ -676,25 +524,25 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
676 | #endif | 524 | #endif |
677 | 525 | ||
678 | /* Update the utmp file. This tty is ours now! */ | 526 | /* Update the utmp file. This tty is ours now! */ |
679 | update_utmp(pid, LOGIN_PROCESS, options.tty, "LOGIN", fakehost); | 527 | update_utmp(pid, LOGIN_PROCESS, G.tty, "LOGIN", fakehost); |
680 | 528 | ||
681 | /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ | 529 | /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ |
682 | debug("calling termios_init\n"); | 530 | debug("calling termios_init\n"); |
683 | termios_init(&termios, options.speeds[0]); | 531 | termios_init(G.speeds[0]); |
684 | 532 | ||
685 | /* Write the modem init string and DON'T flush the buffers */ | 533 | /* Write the modem init string and DON'T flush the buffers */ |
686 | if (option_mask32 & F_INITSTRING) { | 534 | if (option_mask32 & F_INITSTRING) { |
687 | debug("writing init string\n"); | 535 | debug("writing init string\n"); |
688 | full_write1_str(options.initstring); | 536 | full_write1_str(G.initstring); |
689 | } | 537 | } |
690 | 538 | ||
691 | /* Optionally detect the baud rate from the modem status message */ | 539 | /* Optionally detect the baud rate from the modem status message */ |
692 | debug("before autobaud\n"); | 540 | debug("before autobaud\n"); |
693 | if (option_mask32 & F_PARSE) | 541 | if (option_mask32 & F_PARSE) |
694 | auto_baud(line_buf, sizeof(line_buf), &termios); | 542 | auto_baud(); |
695 | 543 | ||
696 | /* Set the optional timer */ | 544 | /* Set the optional timer */ |
697 | alarm(options.timeout); /* if 0, alarm is not set */ | 545 | alarm(G.timeout); /* if 0, alarm is not set */ |
698 | 546 | ||
699 | /* Optionally wait for CR or LF before writing /etc/issue */ | 547 | /* Optionally wait for CR or LF before writing /etc/issue */ |
700 | if (option_mask32 & F_WAITCRLF) { | 548 | if (option_mask32 & F_WAITCRLF) { |
@@ -703,7 +551,6 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
703 | debug("waiting for cr-lf\n"); | 551 | debug("waiting for cr-lf\n"); |
704 | while (safe_read(STDIN_FILENO, &ch, 1) == 1) { | 552 | while (safe_read(STDIN_FILENO, &ch, 1) == 1) { |
705 | debug("read %x\n", (unsigned char)ch); | 553 | debug("read %x\n", (unsigned char)ch); |
706 | ch &= 0x7f; /* strip "parity bit" */ | ||
707 | if (ch == '\n' || ch == '\r') | 554 | if (ch == '\n' || ch == '\r') |
708 | break; | 555 | break; |
709 | } | 556 | } |
@@ -712,20 +559,19 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
712 | logname = NULL; | 559 | logname = NULL; |
713 | if (!(option_mask32 & F_NOPROMPT)) { | 560 | if (!(option_mask32 & F_NOPROMPT)) { |
714 | /* NB: termios_init already set line speed | 561 | /* NB: termios_init already set line speed |
715 | * to options.speeds[0] */ | 562 | * to G.speeds[0] */ |
716 | int baud_index = 0; | 563 | int baud_index = 0; |
717 | 564 | ||
718 | while (1) { | 565 | while (1) { |
719 | /* Read the login name. */ | 566 | /* Read the login name. */ |
720 | debug("reading login name\n"); | 567 | debug("reading login name\n"); |
721 | logname = get_logname(line_buf, sizeof(line_buf), | 568 | logname = get_logname(); |
722 | &options, &chardata); | ||
723 | if (logname) | 569 | if (logname) |
724 | break; | 570 | break; |
725 | /* we are here only if options.numspeed > 1 */ | 571 | /* We are here only if G.numspeed > 1. */ |
726 | baud_index = (baud_index + 1) % options.numspeed; | 572 | baud_index = (baud_index + 1) % G.numspeed; |
727 | cfsetspeed(&termios, options.speeds[baud_index]); | 573 | cfsetspeed(&G.termios, G.speeds[baud_index]); |
728 | tcsetattr_stdin_TCSANOW(&termios); | 574 | tcsetattr_stdin_TCSANOW(&G.termios); |
729 | } | 575 | } |
730 | } | 576 | } |
731 | 577 | ||
@@ -733,7 +579,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
733 | alarm(0); | 579 | alarm(0); |
734 | 580 | ||
735 | /* Finalize the termios settings. */ | 581 | /* Finalize the termios settings. */ |
736 | termios_final(&termios, &chardata); | 582 | termios_final(); |
737 | 583 | ||
738 | /* Now the newline character should be properly written. */ | 584 | /* Now the newline character should be properly written. */ |
739 | full_write(STDOUT_FILENO, "\n", 1); | 585 | full_write(STDOUT_FILENO, "\n", 1); |
@@ -742,6 +588,6 @@ int getty_main(int argc UNUSED_PARAM, char **argv) | |||
742 | /* We use PATH because we trust that root doesn't set "bad" PATH, | 588 | /* We use PATH because we trust that root doesn't set "bad" PATH, |
743 | * and getty is not suid-root applet. */ | 589 | * and getty is not suid-root applet. */ |
744 | /* With -n, logname == NULL, and login will ask for username instead */ | 590 | /* With -n, logname == NULL, and login will ask for username instead */ |
745 | BB_EXECLP(options.login, options.login, "--", logname, NULL); | 591 | BB_EXECLP(G.login, G.login, "--", logname, NULL); |
746 | bb_error_msg_and_die("can't execute '%s'", options.login); | 592 | bb_error_msg_and_die("can't execute '%s'", G.login); |
747 | } | 593 | } |