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