aboutsummaryrefslogtreecommitdiff
path: root/loginutils
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-12-04 09:48:40 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-12-04 09:48:40 +0000
commitd0bbbdcd6eefd249637f153f9d29b37c7f545e33 (patch)
treed2a4453c90ae1d7fc1090a907ad8fe3aa21429fe /loginutils
parent7221c8c22dd527700204eb5cc4d0651af4273f4f (diff)
downloadbusybox-w32-d0bbbdcd6eefd249637f153f9d29b37c7f545e33.tar.gz
busybox-w32-d0bbbdcd6eefd249637f153f9d29b37c7f545e33.tar.bz2
busybox-w32-d0bbbdcd6eefd249637f153f9d29b37c7f545e33.zip
getty: don't accept ancient '#' and '@' as backspace/kill line,
it only confuses people. (Alexander Griesser <alexander.griesser@lkh-vil.or.at> (LKH Villach)) various other cleanups. function old new delta getty_main 2526 2546 +20 static.baud_index 4 - -4 parse_speeds 91 - -91 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 1/0 up/down: 20/-95) Total: -75 bytes text data bss dec hex filename 773152 1086 9008 783246 bf38e busybox_old 773081 1086 9008 783175 bf347 busybox_unstripped
Diffstat (limited to 'loginutils')
-rw-r--r--loginutils/getty.c392
1 files changed, 165 insertions, 227 deletions
diff --git a/loginutils/getty.c b/loginutils/getty.c
index d32d18935..590a05de8 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -33,7 +33,6 @@
33#include <time.h> 33#include <time.h>
34#if ENABLE_FEATURE_WTMP 34#if ENABLE_FEATURE_WTMP
35extern void updwtmp(const char *filename, const struct utmp *ut); 35extern void updwtmp(const char *filename, const struct utmp *ut);
36static void update_utmp(const char *line);
37#endif 36#endif
38#endif /* LOGIN_PROCESS */ 37#endif /* LOGIN_PROCESS */
39 38
@@ -47,6 +46,7 @@ static void update_utmp(const char *line);
47 46
48/* I doubt there are systems which still need this */ 47/* I doubt there are systems which still need this */
49#undef HANDLE_ALLCAPS 48#undef HANDLE_ALLCAPS
49#undef ANCIENT_BS_KILL_CHARS
50 50
51#define _PATH_LOGIN "/bin/login" 51#define _PATH_LOGIN "/bin/login"
52 52
@@ -76,36 +76,20 @@ static void update_utmp(const char *line);
76 * When multiple baud rates are specified on the command line, the first one 76 * When multiple baud rates are specified on the command line, the first one
77 * we will try is the first one specified. 77 * we will try is the first one specified.
78 */ 78 */
79#define FIRST_SPEED 0
80
81/* Storage for command-line options. */
82
83#define MAX_SPEED 10 /* max. nr. of baud rates */ 79#define MAX_SPEED 10 /* max. nr. of baud rates */
84 80
81/* Storage for command-line options. */
85struct options { 82struct options {
86 int flags; /* toggle switches, see below */ 83 int flags; /* toggle switches, see below */
87 unsigned timeout; /* time-out period */ 84 unsigned timeout; /* time-out period */
88 const char *login; /* login program */ 85 const char *login; /* login program */
89 const char *tty; /* name of tty */ 86 const char *tty; /* name of tty */
90 const char *initstring; /* modem init string */ 87 const char *initstring; /* modem init string */
91 const char *issue; /* alternative issue file */ 88 const char *issue; /* alternative issue file */
92 int numspeed; /* number of baud rates to try */ 89 int numspeed; /* number of baud rates to try */
93 int speeds[MAX_SPEED]; /* baud rates to be tried */ 90 int speeds[MAX_SPEED]; /* baud rates to be tried */
94}; 91};
95 92
96static const char opt_string[] ALIGN1 = "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. */ 93/* Storage for things detected while the login name was read. */
110struct chardata { 94struct chardata {
111 unsigned char erase; /* erase character */ 95 unsigned char erase; /* erase character */
@@ -117,6 +101,7 @@ struct chardata {
117#endif 101#endif
118}; 102};
119 103
104
120/* Initial values for the above. */ 105/* Initial values for the above. */
121static const struct chardata init_chardata = { 106static const struct chardata init_chardata = {
122 DEF_ERASE, /* default erase character */ 107 DEF_ERASE, /* default erase character */
@@ -128,12 +113,25 @@ static const struct chardata init_chardata = {
128#endif 113#endif
129}; 114};
130 115
131/* The following is used for understandable diagnostics. */ 116static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
117#define F_INITSTRING (1 << 0) /* -I initstring is set */
118#define F_LOCAL (1 << 1) /* -L force local */
119#define F_FAKEHOST (1 << 2) /* -H force fakehost */
120#define F_CUSTISSUE (1 << 3) /* -f give alternative issue file */
121#define F_RTSCTS (1 << 4) /* -h enable RTS/CTS flow control */
122#define F_ISSUE (1 << 5) /* -i display /etc/issue */
123#define F_LOGIN (1 << 6) /* -l non-default login program */
124#define F_PARSE (1 << 7) /* -m process modem status messages */
125#define F_TIMEOUT (1 << 8) /* -t time out */
126#define F_WAITCRLF (1 << 9) /* -w wait for CR or LF */
127#define F_NOPROMPT (1 << 10) /* -n don't ask for login name! */
128
132 129
133/* Fake hostname for ut_host specified on command line. */ 130/* Fake hostname for ut_host specified on command line. */
134static char *fakehost = NULL; 131static char *fakehost = NULL;
132#define line_buf bb_common_bufsiz1
135 133
136/* ... */ 134/* The following is used for understandable diagnostics. */
137#ifdef DEBUGGING 135#ifdef DEBUGGING
138#define debug(s) fprintf(dbf,s); fflush(dbf) 136#define debug(s) fprintf(dbf,s); fflush(dbf)
139#define DEBUGTERM "/dev/ttyp0" 137#define DEBUGTERM "/dev/ttyp0"
@@ -158,14 +156,14 @@ static int bcode(const char *s)
158 return 0; 156 return 0;
159} 157}
160 158
161
162/* parse_speeds - parse alternate baud rates */ 159/* parse_speeds - parse alternate baud rates */
163static void parse_speeds(struct options *op, char *arg) 160static void parse_speeds(struct options *op, char *arg)
164{ 161{
165 char *cp; 162 char *cp;
166 163
164 /* NB: at least one iteration is always done */
167 debug("entered parse_speeds\n"); 165 debug("entered parse_speeds\n");
168 for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { 166 while ((cp = strsep(&arg, ",")) != NULL) {
169 op->speeds[op->numspeed] = bcode(cp); 167 op->speeds[op->numspeed] = bcode(cp);
170 if (op->speeds[op->numspeed] <= 0) 168 if (op->speeds[op->numspeed] <= 0)
171 bb_error_msg_and_die("bad speed: %s", cp); 169 bb_error_msg_and_die("bad speed: %s", cp);
@@ -173,18 +171,19 @@ static void parse_speeds(struct options *op, char *arg)
173 if (op->numspeed > MAX_SPEED) 171 if (op->numspeed > MAX_SPEED)
174 bb_error_msg_and_die("too many alternate speeds"); 172 bb_error_msg_and_die("too many alternate speeds");
175 } 173 }
176 debug("exiting parsespeeds\n"); 174 debug("exiting parse_speeds\n");
177} 175}
178 176
179
180/* parse_args - parse command-line arguments */ 177/* parse_args - parse command-line arguments */
181static void parse_args(int argc, char **argv, struct options *op) 178static void parse_args(char **argv, struct options *op)
182{ 179{
183 char *ts; 180 char *ts;
184 181
182 opt_complementary = "-2"; /* at least 2 args */
185 op->flags = getopt32(argv, opt_string, 183 op->flags = getopt32(argv, opt_string,
186 &(op->initstring), &fakehost, &(op->issue), 184 &(op->initstring), &fakehost, &(op->issue),
187 &(op->login), &ts); 185 &(op->login), &ts);
186 argv += optind;
188 if (op->flags & F_INITSTRING) { 187 if (op->flags & F_INITSTRING) {
189 const char *p = op->initstring; 188 const char *p = op->initstring;
190 char *q; 189 char *q;
@@ -202,45 +201,40 @@ static void parse_args(int argc, char **argv, struct options *op)
202 } 201 }
203 *q = '\0'; 202 *q = '\0';
204 } 203 }
205 op->flags ^= F_ISSUE; /* revert flag show /etc/issue */ 204 op->flags ^= F_ISSUE; /* invert flag show /etc/issue */
206 if (op->flags & F_TIMEOUT) { 205 if (op->flags & F_TIMEOUT) {
207 op->timeout = xatoul_range(ts, 1, INT_MAX); 206 op->timeout = xatoi_u(ts);
208 } 207 }
209 argv += optind; 208 debug("after getopt\n");
210 argc -= optind;
211 debug("after getopt loop\n");
212 if (argc < 2) /* check parameter count */
213 bb_show_usage();
214 209
215 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ 210 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
211 op->tty = argv[0]; /* tty name */
212 ts = argv[1]; /* baud rate(s) */
216 if (isdigit(argv[0][0])) { 213 if (isdigit(argv[0][0])) {
217 /* a number first, assume it's a speed (BSD style) */ 214 /* a number first, assume it's a speed (BSD style) */
218 parse_speeds(op, argv[0]); /* baud rate(s) */ 215 op->tty = ts; /* tty name is in argv[1] */
219 op->tty = argv[1]; /* tty name */ 216 ts = argv[0]; /* baud rate(s) */
220 } else {
221 op->tty = argv[0]; /* tty name */
222 parse_speeds(op, argv[1]); /* baud rate(s) */
223 } 217 }
218 parse_speeds(op, ts);
224 219
225 if (argv[2]) 220 if (argv[2])
226 setenv("TERM", argv[2], 1); 221 setenv("TERM", argv[2], 1);
227 222
228 debug("exiting parseargs\n"); 223 debug("exiting parse_args\n");
229} 224}
230 225
231/* open_tty - set up tty as standard { input, output, error } */ 226/* open_tty - set up tty as standard { input, output, error } */
232static void open_tty(const char *tty, struct termios *tp, int local) 227static void open_tty(const char *tty)
233{ 228{
234 int chdir_to_root = 0;
235
236 /* Set up new standard input, unless we are given an already opened port. */ 229 /* Set up new standard input, unless we are given an already opened port. */
237 if (NOT_LONE_DASH(tty)) { 230 if (NOT_LONE_DASH(tty)) {
238 struct stat st; 231 struct stat st;
232 int cur_dir_fd;
239 int fd; 233 int fd;
240 234
241 /* Sanity checks... */ 235 /* Sanity checks... */
236 cur_dir_fd = xopen(".", O_DIRECTORY | O_NONBLOCK);
242 xchdir("/dev"); 237 xchdir("/dev");
243 chdir_to_root = 1;
244 xstat(tty, &st); 238 xstat(tty, &st);
245 if ((st.st_mode & S_IFMT) != S_IFCHR) 239 if ((st.st_mode & S_IFMT) != S_IFCHR)
246 bb_error_msg_and_die("%s: not a character device", tty); 240 bb_error_msg_and_die("%s: not a character device", tty);
@@ -248,9 +242,23 @@ static void open_tty(const char *tty, struct termios *tp, int local)
248 /* Open the tty as standard input. */ 242 /* Open the tty as standard input. */
249 debug("open(2)\n"); 243 debug("open(2)\n");
250 fd = xopen(tty, O_RDWR | O_NONBLOCK); 244 fd = xopen(tty, O_RDWR | O_NONBLOCK);
245
246 /* Restore current directory */
247 fchdir(cur_dir_fd);
248
249 /* Open the tty as standard input, continued */
251 xdup2(fd, 0); 250 xdup2(fd, 0);
251 /* fd is >= cur_dir_fd, and cur_dir_fd gets closed too here: */
252 while (fd > 2) 252 while (fd > 2)
253 close(fd--); 253 close(fd--);
254
255 /* Set proper protections and ownership. Mode 0622
256 * is suitable for SYSV < 4 because /bin/login does not change
257 * protections. SunOS 4 login will change the protections to 0620
258 * (write access for group tty) after the login has succeeded.
259 */
260 fchown(0, 0, 0); /* 0:0 */
261 fchmod(0, 0622); /* crw--w--w- */
254 } else { 262 } else {
255 /* 263 /*
256 * Standard input should already be connected to an open port. Make 264 * Standard input should already be connected to an open port. Make
@@ -259,71 +267,6 @@ static void open_tty(const char *tty, struct termios *tp, int local)
259 if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR) 267 if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR)
260 bb_error_msg_and_die("stdin is not open for read/write"); 268 bb_error_msg_and_die("stdin is not open for read/write");
261 } 269 }
262
263 /* Replace current standard output/error fd's with new ones */
264 debug("duping\n");
265 xdup2(0, 1);
266 xdup2(0, 2);
267
268 /*
269 * The following ioctl will fail if stdin is not a tty, but also when
270 * there is noise on the modem control lines. In the latter case, the
271 * common course of action is (1) fix your cables (2) give the modem more
272 * time to properly reset after hanging up. SunOS users can achieve (2)
273 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
274 * 5 seconds seems to be a good value.
275 */
276 ioctl_or_perror_and_die(0, TCGETS, tp, "%s: TCGETS", tty);
277
278 /*
279 * It seems to be a terminal. Set proper protections and ownership. Mode
280 * 0622 is suitable for SYSV <4 because /bin/login does not change
281 * protections. SunOS 4 login will change the protections to 0620 (write
282 * access for group tty) after the login has succeeded.
283 */
284
285#ifdef DEBIAN
286#warning Debian /dev/vcs[a]NN hack is deprecated and will be removed
287 {
288 /* tty to root.dialout 660 */
289 struct group *gr;
290 int id;
291
292 gr = getgrnam("dialout");
293 id = gr ? gr->gr_gid : 0;
294 chown(tty, 0, id);
295 chmod(tty, 0660);
296
297 /* vcs,vcsa to root.sys 600 */
298 if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) {
299 char *vcs, *vcsa;
300
301 vcs = xstrdup(tty);
302 vcsa = xmalloc(strlen(tty) + 2);
303 strcpy(vcs, "vcs");
304 strcpy(vcs + 3, tty + 3);
305 strcpy(vcsa, "vcsa");
306 strcpy(vcsa + 4, tty + 3);
307
308 gr = getgrnam("sys");
309 id = gr ? gr->gr_gid : 0;
310 chown(vcs, 0, id);
311 chmod(vcs, 0600);
312 chown(vcsa, 0, id);
313 chmod(vcs, 0600);
314
315 free(vcs);
316 free(vcsa);
317 }
318 }
319#else
320 if (NOT_LONE_DASH(tty)) {
321 chown(tty, 0, 0); /* 0:0 */
322 chmod(tty, 0622); /* crw--w--w- */
323 }
324#endif
325 if (chdir_to_root)
326 xchdir("/");
327} 270}
328 271
329/* termios_init - initialize termios settings */ 272/* termios_init - initialize termios settings */
@@ -351,17 +294,13 @@ static void termios_init(struct termios *tp, int speed, struct options *op)
351 tp->c_cc[VTIME] = 0; 294 tp->c_cc[VTIME] = 0;
352 295
353 /* Optionally enable hardware flow control */ 296 /* Optionally enable hardware flow control */
354 297#ifdef CRTSCTS
355#ifdef CRTSCTS
356 if (op->flags & F_RTSCTS) 298 if (op->flags & F_RTSCTS)
357 tp->c_cflag |= CRTSCTS; 299 tp->c_cflag |= CRTSCTS;
358#endif 300#endif
359 301
360 ioctl(0, TCSETS, tp); 302 ioctl(0, TCSETS, tp);
361 303
362 /* go to blocking input even in local mode */
363 ndelay_off(0);
364
365 debug("term_io 2\n"); 304 debug("term_io 2\n");
366} 305}
367 306
@@ -393,26 +332,24 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp)
393 * Use 7-bit characters, don't block if input queue is empty. Errors will 332 * Use 7-bit characters, don't block if input queue is empty. Errors will
394 * be dealt with later on. 333 * be dealt with later on.
395 */ 334 */
396
397 iflag = tp->c_iflag; 335 iflag = tp->c_iflag;
398 tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ 336 tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
399 vmin = tp->c_cc[VMIN]; 337 vmin = tp->c_cc[VMIN];
400 tp->c_cc[VMIN] = 0; /* don't block if queue empty */ 338 tp->c_cc[VMIN] = 0; /* don't block if queue empty */
401 ioctl(0, TCSETS, tp); 339 ioctl(0, TCSETS, tp);
402 340
403 /* 341 /*
404 * Wait for a while, then read everything the modem has said so far and 342 * Wait for a while, then read everything the modem has said so far and
405 * try to extract the speed of the dial-in call. 343 * try to extract the speed of the dial-in call.
406 */ 344 */
407
408 sleep(1); 345 sleep(1);
409 nread = read(0, buf, size_buf - 1); 346 nread = safe_read(0, buf, size_buf - 1);
410 if (nread > 0) { 347 if (nread > 0) {
411 buf[nread] = '\0'; 348 buf[nread] = '\0';
412 for (bp = buf; bp < buf + nread; bp++) { 349 for (bp = buf; bp < buf + nread; bp++) {
413 if (isascii(*bp) && isdigit(*bp)) { 350 if (isdigit(*bp)) {
414 speed = bcode(bp); 351 speed = bcode(bp);
415 if (speed) { 352 if (speed > 0) {
416 tp->c_cflag &= ~CBAUD; 353 tp->c_cflag &= ~CBAUD;
417 tp->c_cflag |= speed; 354 tp->c_cflag |= speed;
418 } 355 }
@@ -420,25 +357,13 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp)
420 } 357 }
421 } 358 }
422 } 359 }
423 /* Restore terminal settings. Errors will be dealt with later on. */
424 360
361 /* Restore terminal settings. Errors will be dealt with later on. */
425 tp->c_iflag = iflag; 362 tp->c_iflag = iflag;
426 tp->c_cc[VMIN] = vmin; 363 tp->c_cc[VMIN] = vmin;
427 ioctl(0, TCSETS, tp); 364 ioctl(0, TCSETS, tp);
428} 365}
429 366
430/* next_speed - select next baud rate */
431static void next_speed(struct termios *tp, struct options *op)
432{
433 static int baud_index = FIRST_SPEED; /* current speed index */
434
435 baud_index = (baud_index + 1) % op->numspeed;
436 tp->c_cflag &= ~CBAUD;
437 tp->c_cflag |= op->speeds[baud_index];
438 ioctl(0, TCSETS, tp);
439}
440
441
442/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ 367/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
443static void do_prompt(struct options *op, struct termios *tp) 368static void do_prompt(struct options *op, struct termios *tp)
444{ 369{
@@ -449,9 +374,9 @@ static void do_prompt(struct options *op, struct termios *tp)
449} 374}
450 375
451#ifdef HANDLE_ALLCAPS 376#ifdef HANDLE_ALLCAPS
452/* caps_lock - string contains upper case without lower case */ 377/* all_is_upcase - string contains upper case without lower case */
453/* returns 1 if true, 0 if false */ 378/* returns 1 if true, 0 if false */
454static int caps_lock(const char *s) 379static int all_is_upcase(const char *s)
455{ 380{
456 while (*s) 381 while (*s)
457 if (islower(*s++)) 382 if (islower(*s++))
@@ -460,8 +385,8 @@ static int caps_lock(const char *s)
460} 385}
461#endif 386#endif
462 387
463/* get_logname - get user name, establish parity, speed, erase, kill, eol */ 388/* get_logname - get user name, establish parity, speed, erase, kill, eol;
464/* return NULL on failure, logname on success */ 389 * return NULL on BREAK, logname on success */
465static char *get_logname(char *logname, unsigned size_logname, 390static char *get_logname(char *logname, unsigned size_logname,
466 struct options *op, struct chardata *cp, struct termios *tp) 391 struct options *op, struct chardata *cp, struct termios *tp)
467{ 392{
@@ -477,26 +402,19 @@ static char *get_logname(char *logname, unsigned size_logname,
477 "\210\240\210", /* no parity */ 402 "\210\240\210", /* no parity */
478 }; 403 };
479 404
480 /* Initialize kill, erase, parity etc. (also after switching speeds). */ 405 /* NB: *cp is pre-initialized with init_chardata */
481
482 *cp = init_chardata;
483 406
484 /* Flush pending input (esp. after parsing or switching the baud rate). */ 407 /* Flush pending input (esp. after parsing or switching the baud rate). */
485
486 sleep(1); 408 sleep(1);
487 ioctl(0, TCFLSH, TCIFLUSH); 409 ioctl(0, TCFLSH, TCIFLUSH);
488 410
489 /* Prompt for and read a login name. */ 411 /* Prompt for and read a login name. */
490
491 logname[0] = '\0'; 412 logname[0] = '\0';
492 while (!logname[0]) { 413 while (!logname[0]) {
493
494 /* Write issue file and prompt, with "parity" bit == 0. */ 414 /* Write issue file and prompt, with "parity" bit == 0. */
495
496 do_prompt(op, tp); 415 do_prompt(op, tp);
497 416
498 /* Read name, watch for break, parity, erase, kill, end-of-line. */ 417 /* Read name, watch for break, parity, erase, kill, end-of-line. */
499
500 bp = logname; 418 bp = logname;
501 cp->eol = '\0'; 419 cp->eol = '\0';
502 while (cp->eol == '\0') { 420 while (cp->eol == '\0') {
@@ -508,7 +426,8 @@ static char *get_logname(char *logname, unsigned size_logname,
508 bb_perror_msg_and_die("%s: read", op->tty); 426 bb_perror_msg_and_die("%s: read", op->tty);
509 } 427 }
510 428
511 /* Do BREAK handling elsewhere. */ 429 /* BREAK. If we have speeds to try,
430 * return NULL (will switch speeds and return here) */
512 if (c == '\0' && op->numspeed > 1) 431 if (c == '\0' && op->numspeed > 1)
513 return NULL; 432 return NULL;
514 433
@@ -535,18 +454,22 @@ static char *get_logname(char *logname, unsigned size_logname,
535 break; 454 break;
536 case BS: 455 case BS:
537 case DEL: 456 case DEL:
457#ifdef ANCIENT_BS_KILL_CHARS
538 case '#': 458 case '#':
459#endif
539 cp->erase = ascval; /* set erase character */ 460 cp->erase = ascval; /* set erase character */
540 if (bp > logname) { 461 if (bp > logname) {
541 write(1, erase[cp->parity], 3); 462 full_write(1, erase[cp->parity], 3);
542 bp--; 463 bp--;
543 } 464 }
544 break; 465 break;
545 case CTL('U'): 466 case CTL('U'):
467#ifdef ANCIENT_BS_KILL_CHARS
546 case '@': 468 case '@':
469#endif
547 cp->kill = ascval; /* set kill character */ 470 cp->kill = ascval; /* set kill character */
548 while (bp > logname) { 471 while (bp > logname) {
549 write(1, erase[cp->parity], 3); 472 full_write(1, erase[cp->parity], 3);
550 bp--; 473 bp--;
551 } 474 }
552 break; 475 break;
@@ -558,7 +481,7 @@ static char *get_logname(char *logname, unsigned size_logname,
558 } else if (bp - logname >= size_logname - 1) { 481 } else if (bp - logname >= size_logname - 1) {
559 bb_error_msg_and_die("%s: input overrun", op->tty); 482 bb_error_msg_and_die("%s: input overrun", op->tty);
560 } else { 483 } else {
561 write(1, &c, 1); /* echo the character */ 484 full_write(1, &c, 1); /* echo the character */
562 *bp++ = ascval; /* and store it */ 485 *bp++ = ascval; /* and store it */
563 } 486 }
564 break; 487 break;
@@ -568,7 +491,7 @@ static char *get_logname(char *logname, unsigned size_logname,
568 /* Handle names with upper case and no lower case. */ 491 /* Handle names with upper case and no lower case. */
569 492
570#ifdef HANDLE_ALLCAPS 493#ifdef HANDLE_ALLCAPS
571 cp->capslock = caps_lock(logname); 494 cp->capslock = all_is_upcase(logname);
572 if (cp->capslock) { 495 if (cp->capslock) {
573 for (bp = logname; *bp; bp++) 496 for (bp = logname; *bp; bp++)
574 if (isupper(*bp)) 497 if (isupper(*bp))
@@ -641,7 +564,6 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat
641 ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); 564 ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty);
642} 565}
643 566
644
645#ifdef SYSV_STYLE 567#ifdef SYSV_STYLE
646#if ENABLE_FEATURE_UTMP 568#if ENABLE_FEATURE_UTMP
647/* update_utmp - update our utmp entry */ 569/* update_utmp - update our utmp entry */
@@ -666,17 +588,16 @@ static void update_utmp(const char *line)
666 utmpname(_PATH_UTMP); 588 utmpname(_PATH_UTMP);
667 setutent(); 589 setutent();
668 while ((utp = getutent()) 590 while ((utp = getutent())
669 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) 591 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)
670 /* nothing */; 592 ) {
593 continue;
594 }
671 595
672 if (utp) { 596 /* some inits don't initialize utmp... */
597 memset(&ut, 0, sizeof(ut));
598 safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
599 if (utp)
673 memcpy(&ut, utp, sizeof(ut)); 600 memcpy(&ut, utp, sizeof(ut));
674 } else {
675 /* some inits don't initialize utmp... */
676 memset(&ut, 0, sizeof(ut));
677 safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
678 }
679 /* endutent(); */
680 601
681 strcpy(ut.ut_user, "LOGIN"); 602 strcpy(ut.ut_user, "LOGIN");
682 safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line)); 603 safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line));
@@ -700,42 +621,43 @@ static void update_utmp(const char *line)
700#endif /* CONFIG_FEATURE_UTMP */ 621#endif /* CONFIG_FEATURE_UTMP */
701#endif /* SYSV_STYLE */ 622#endif /* SYSV_STYLE */
702 623
703
704int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 624int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
705int getty_main(int argc, char **argv) 625int getty_main(int argc, char **argv)
706{ 626{
707 int nullfd; 627 int n;
708 char *logname = NULL; /* login name, given to /bin/login */ 628 char *logname; /* login name, given to /bin/login */
709 /* Merging these into "struct local" may _seem_ to reduce 629 /* Merging these into "struct local" may _seem_ to reduce
710 * parameter passing, but today's gcc will inline 630 * parameter passing, but today's gcc will inline
711 * statics which are called once anyway, so don't do that */ 631 * statics which are called once anyway, so don't do that */
712 struct chardata chardata; /* set by get_logname() */ 632 struct chardata chardata; /* set by get_logname() */
713 struct termios termios; /* terminal mode bits */ 633 struct termios termios; /* terminal mode bits */
714 struct options options = { 634 struct options options;
715 0, /* show /etc/issue (SYSV_STYLE) */ 635
716 0, /* no timeout */ 636 memset(&options, 0, sizeof(options));
717 _PATH_LOGIN, /* default login program */ 637 options.login = _PATH_LOGIN; /* default login program */
718 "tty1", /* default tty line */ 638 options.tty = "tty1"; /* default tty line */
719 "", /* modem init string */ 639 options.initstring = ""; /* modem init string */
720#ifdef ISSUE 640#ifdef ISSUE
721 ISSUE, /* default issue file */ 641 options.issue = ISSUE; /* default issue file */
722#else
723 NULL,
724#endif 642#endif
725 0, /* no baud rates known yet */
726 };
727 643
728 /* Already too late because of theoretical 644 /* Already too late because of theoretical
729 * possibility of getty --help somehow triggered 645 * possibility of getty --help somehow triggered
730 * inadvertently before we reach this. Oh well. */ 646 * inadvertently before we reach this. Oh well. */
731 logmode = LOGMODE_NONE; 647 logmode = LOGMODE_NONE;
648
649 /* Create new session, lose controlling tty, if any */
650 /* docs/ctty.htm says:
651 * "This is allowed only when the current process
652 * is not a process group leader" - is this a problem? */
732 setsid(); 653 setsid();
733 nullfd = xopen(bb_dev_null, O_RDWR); 654
734 /* dup2(nullfd, 0); - no, because of possible "getty - 9600" */ 655 n = xopen(bb_dev_null, O_RDWR);
735 /* open_tty() will take care of fd# 0 anyway */ 656 /* dup2(n, 0); - no, because of possible "getty - 9600" */
736 dup2(nullfd, 1); 657 dup2(n, 1);
737 dup2(nullfd, 2); 658 dup2(n, 2);
738 while (nullfd > 2) close(nullfd--); 659 while (n > 2)
660 close(n--);
739 /* We want special flavor of error_msg_and_die */ 661 /* We want special flavor of error_msg_and_die */
740 die_sleep = 10; 662 die_sleep = 10;
741 msg_eol = "\r\n"; 663 msg_eol = "\r\n";
@@ -744,69 +666,74 @@ int getty_main(int argc, char **argv)
744 666
745#ifdef DEBUGGING 667#ifdef DEBUGGING
746 dbf = xfopen(DEBUGTERM, "w"); 668 dbf = xfopen(DEBUGTERM, "w");
747 669 for (n = 1; n < argc; n++) {
748 { 670 debug(argv[n]);
749 int i; 671 debug("\n");
750
751 for (i = 1; i < argc; i++) {
752 debug(argv[i]);
753 debug("\n");
754 }
755 } 672 }
756#endif 673#endif
757 674
758 /* Parse command-line arguments. */ 675 /* Parse command-line arguments. */
759 parse_args(argc, argv, &options); 676 parse_args(argv, &options);
677
678 debug("calling open_tty\n");
679 /* Open the tty as standard input, if it is not "-" */
680 open_tty(options.tty);
681
682 debug("duping\n");
683 ndelay_off(0);
684 xdup2(0, 1);
685 xdup2(0, 2);
686
687 /*
688 * The following ioctl will fail if stdin is not a tty, but also when
689 * there is noise on the modem control lines. In the latter case, the
690 * common course of action is (1) fix your cables (2) give the modem more
691 * time to properly reset after hanging up. SunOS users can achieve (2)
692 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
693 * 5 seconds seems to be a good value.
694 */
695 ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty);
760 696
761#ifdef SYSV_STYLE 697#ifdef SYSV_STYLE
762#if ENABLE_FEATURE_UTMP 698#if ENABLE_FEATURE_UTMP
763 /* Update the utmp file. */ 699 /* Update the utmp file */
764 update_utmp(options.tty); 700 update_utmp(options.tty);
765#endif 701#endif
766#endif 702#endif
767 703
768 debug("calling open_tty\n");
769 /* Open the tty as standard { input, output, error }. */
770 open_tty(options.tty, &termios, options.flags & F_LOCAL);
771
772#ifdef __linux__ 704#ifdef __linux__
773 { 705 /* Make ourself a foreground process group within our session */
774 int iv; 706 tcsetpgrp(0, getpid());
775 707 // /* Forcibly make fd 0 our controlling tty, even if another session
776 iv = getpid(); 708 // * has it as a ctty. (Another session loses ctty). */
777 ioctl(0, TIOCSPGRP, &iv); 709 // ioctl(0, TIOCSCTTY, (void*)1);
778 }
779#endif 710#endif
711
780 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ 712 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
781 debug("calling termios_init\n"); 713 debug("calling termios_init\n");
782 termios_init(&termios, options.speeds[FIRST_SPEED], &options); 714 termios_init(&termios, options.speeds[0], &options);
783 715
784 /* write the modem init string and DON'T flush the buffers */ 716 /* Write the modem init string and DON'T flush the buffers */
785 if (options.flags & F_INITSTRING) { 717 if (options.flags & F_INITSTRING) {
786 debug("writing init string\n"); 718 debug("writing init string\n");
787 write(1, options.initstring, strlen(options.initstring)); 719 full_write(1, options.initstring, strlen(options.initstring));
788 }
789
790 if (!(options.flags & F_LOCAL)) {
791 /* go to blocking write mode unless -L is specified */
792 ndelay_off(1);
793 } 720 }
794 721
795 /* Optionally detect the baud rate from the modem status message. */ 722 /* Optionally detect the baud rate from the modem status message */
796 debug("before autobaud\n"); 723 debug("before autobaud\n");
797 if (options.flags & F_PARSE) 724 if (options.flags & F_PARSE)
798 auto_baud(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), &termios); 725 auto_baud(line_buf, sizeof(line_buf), &termios);
799 726
800 /* Set the optional timer. */ 727 /* Set the optional timer */
801 if (options.timeout) 728 if (options.timeout)
802 alarm(options.timeout); 729 alarm(options.timeout);
803 730
804 /* optionally wait for CR or LF before writing /etc/issue */ 731 /* Optionally wait for CR or LF before writing /etc/issue */
805 if (options.flags & F_WAITCRLF) { 732 if (options.flags & F_WAITCRLF) {
806 char ch; 733 char ch;
807 734
808 debug("waiting for cr-lf\n"); 735 debug("waiting for cr-lf\n");
809 while (read(0, &ch, 1) == 1) { 736 while (safe_read(0, &ch, 1) == 1) {
810 ch &= 0x7f; /* strip "parity bit" */ 737 ch &= 0x7f; /* strip "parity bit" */
811#ifdef DEBUGGING 738#ifdef DEBUGGING
812 fprintf(dbf, "read %c\n", ch); 739 fprintf(dbf, "read %c\n", ch);
@@ -816,31 +743,42 @@ int getty_main(int argc, char **argv)
816 } 743 }
817 } 744 }
818 745
746 logname = NULL;
819 chardata = init_chardata; 747 chardata = init_chardata;
820 if (!(options.flags & F_NOPROMPT)) { 748 if (!(options.flags & F_NOPROMPT)) {
821 /* Read the login name. */ 749 /* NB:termios_init already set line speed
822 debug("reading login name\n"); 750 * to options.speeds[0] */
823 logname = get_logname(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), 751 int baud_index = 0;
752
753 while (1) {
754 /* Read the login name. */
755 debug("reading login name\n");
756 logname = get_logname(line_buf, sizeof(line_buf),
824 &options, &chardata, &termios); 757 &options, &chardata, &termios);
825 while (logname == NULL) 758 if (logname)
826 next_speed(&termios, &options); 759 break;
760 /* we are here only if options.numspeed > 1 */
761 baud_index = (baud_index + 1) % options.numspeed;
762 termios.c_cflag &= ~CBAUD;
763 termios.c_cflag |= options.speeds[baud_index];
764 ioctl(0, TCSETS, &termios);
765 }
827 } 766 }
828 767
829 /* Disable timer. */ 768 /* Disable timer. */
830
831 if (options.timeout) 769 if (options.timeout)
832 alarm(0); 770 alarm(0);
833 771
834 /* Finalize the termios settings. */ 772 /* Finalize the termios settings. */
835
836 termios_final(&options, &termios, &chardata); 773 termios_final(&options, &termios, &chardata);
837 774
838 /* Now the newline character should be properly written. */ 775 /* Now the newline character should be properly written. */
839 776 full_write(1, "\n", 1);
840 write(1, "\n", 1);
841 777
842 /* Let the login program take care of password validation. */ 778 /* Let the login program take care of password validation. */
843 779 /* We use PATH because we trust that root doesn't set "bad" PATH,
844 execl(options.login, options.login, "--", logname, (char *) 0); 780 * and getty is not suid-root applet. */
781 /* Hmm... with -n, logname == NULL! Is it ok? */
782 BB_EXECLP(options.login, options.login, "--", logname, NULL);
845 bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login); 783 bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login);
846} 784}