]>
Commit | Line | Data |
---|---|---|
1815bff5 A |
1 | /*- |
2 | * Copyright (c) 1980, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
34d340d7 | 4 | * Portions copyright (c) 2007 Apple Inc. All rights reserved. |
1815bff5 A |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
34d340d7 | 35 | #include <sys/cdefs.h> |
1815bff5 | 36 | #ifndef lint |
cf37c299 | 37 | __unused static const char copyright[] = |
1815bff5 A |
38 | "@(#) Copyright (c) 1980, 1993\n\ |
39 | The Regents of the University of California. All rights reserved.\n"; | |
40 | #endif /* not lint */ | |
41 | ||
42 | #ifndef lint | |
34d340d7 A |
43 | #if 0 |
44 | static char sccsid[] = "@(#)from: main.c 8.1 (Berkeley) 6/20/93"; | |
45 | #endif | |
cf37c299 | 46 | __unused static const char rcsid[] = |
34d340d7 | 47 | "$FreeBSD: src/libexec/getty/main.c,v 1.47 2005/04/06 17:42:24 stefanf Exp $"; |
1815bff5 A |
48 | #endif /* not lint */ |
49 | ||
50 | #include <sys/param.h> | |
1815bff5 | 51 | #include <sys/ioctl.h> |
34d340d7 | 52 | #include <sys/time.h> |
1815bff5 | 53 | #include <sys/resource.h> |
34d340d7 A |
54 | #include <sys/stat.h> |
55 | #include <sys/ttydefaults.h> | |
1815bff5 | 56 | #include <sys/utsname.h> |
34d340d7 | 57 | |
1815bff5 | 58 | #include <ctype.h> |
34d340d7 | 59 | #include <errno.h> |
1815bff5 | 60 | #include <fcntl.h> |
34d340d7 | 61 | #include <locale.h> |
fc6d9e4b A |
62 | #ifdef __APPLE__ |
63 | #include <util.h> | |
64 | #else | |
34d340d7 | 65 | #include <libutil.h> |
fc6d9e4b | 66 | #endif |
1815bff5 A |
67 | #include <setjmp.h> |
68 | #include <signal.h> | |
69 | #include <stdlib.h> | |
70 | #include <string.h> | |
71 | #include <syslog.h> | |
34d340d7 | 72 | #include <termios.h> |
1815bff5 A |
73 | #include <time.h> |
74 | #include <unistd.h> | |
75 | ||
34d340d7 A |
76 | #ifdef __APPLE__ |
77 | #include <TargetConditionals.h> | |
78 | #endif | |
79 | ||
1815bff5 | 80 | #include "gettytab.h" |
1815bff5 | 81 | #include "extern.h" |
34d340d7 | 82 | #include "pathnames.h" |
1815bff5 A |
83 | |
84 | /* | |
85 | * Set the amount of running time that getty should accumulate | |
86 | * before deciding that something is wrong and exit. | |
87 | */ | |
88 | #define GETTY_TIMEOUT 60 /* seconds */ | |
89 | ||
34d340d7 A |
90 | #undef CTRL |
91 | #define CTRL(x) (x&037) | |
92 | ||
93 | /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ | |
94 | ||
95 | #define PPP_FRAME 0x7e /* PPP Framing character */ | |
96 | #define PPP_STATION 0xff /* "All Station" character */ | |
97 | #define PPP_ESCAPE 0x7d /* Escape Character */ | |
98 | #define PPP_CONTROL 0x03 /* PPP Control Field */ | |
99 | #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ | |
100 | #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ | |
101 | #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ | |
102 | ||
103 | /* original mode; flags've been reset using values from <sys/ttydefaults.h> */ | |
104 | struct termios omode; | |
105 | /* current mode */ | |
106 | struct termios tmode; | |
1815bff5 A |
107 | |
108 | int crmod, digit, lower, upper; | |
109 | ||
110 | char hostname[MAXHOSTNAMELEN]; | |
34d340d7 | 111 | char name[MAXLOGNAME*3]; |
1815bff5 A |
112 | char dev[] = _PATH_DEV; |
113 | char ttyn[32]; | |
1815bff5 A |
114 | |
115 | #define OBUFSIZ 128 | |
116 | #define TABBUFSIZ 512 | |
117 | ||
34d340d7 | 118 | const char *tname; |
1815bff5 A |
119 | |
120 | char *env[128]; | |
121 | ||
122 | char partab[] = { | |
123 | 0001,0201,0201,0001,0201,0001,0001,0201, | |
124 | 0202,0004,0003,0205,0005,0206,0201,0001, | |
125 | 0201,0001,0001,0201,0001,0201,0201,0001, | |
126 | 0001,0201,0201,0001,0201,0001,0001,0201, | |
127 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
128 | 0000,0200,0200,0000,0200,0000,0000,0200, | |
129 | 0000,0200,0200,0000,0200,0000,0000,0200, | |
130 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
131 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
132 | 0000,0200,0200,0000,0200,0000,0000,0200, | |
133 | 0000,0200,0200,0000,0200,0000,0000,0200, | |
134 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
135 | 0000,0200,0200,0000,0200,0000,0000,0200, | |
136 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
137 | 0200,0000,0000,0200,0000,0200,0200,0000, | |
138 | 0000,0200,0200,0000,0200,0000,0000,0201 | |
139 | }; | |
140 | ||
141 | #define ERASE tmode.c_cc[VERASE] | |
142 | #define KILL tmode.c_cc[VKILL] | |
143 | #define EOT tmode.c_cc[VEOF] | |
144 | ||
34d340d7 A |
145 | #define puts Gputs |
146 | ||
147 | static void defttymode(void); | |
148 | static void dingdong(int); | |
149 | static void dogettytab(void); | |
150 | static int getname(void); | |
151 | static void interrupt(int); | |
152 | static void oflush(void); | |
153 | static void prompt(void); | |
154 | static void putchr(int); | |
155 | static void putf(const char *); | |
156 | static void putpad(const char *); | |
157 | static void puts(const char *); | |
158 | static void timeoverrun(int); | |
fc6d9e4b | 159 | static char *getty_getline(int); |
34d340d7 A |
160 | static void setttymode(int); |
161 | static int opentty(const char *, int); | |
162 | ||
1815bff5 A |
163 | jmp_buf timeout; |
164 | ||
165 | static void | |
34d340d7 | 166 | dingdong(int signo __unused) |
1815bff5 | 167 | { |
1815bff5 | 168 | alarm(0); |
1815bff5 A |
169 | longjmp(timeout, 1); |
170 | } | |
171 | ||
172 | jmp_buf intrupt; | |
173 | ||
174 | static void | |
34d340d7 | 175 | interrupt(int signo __unused) |
1815bff5 | 176 | { |
1815bff5 A |
177 | longjmp(intrupt, 1); |
178 | } | |
179 | ||
180 | /* | |
181 | * Action to take when getty is running too long. | |
182 | */ | |
34d340d7 A |
183 | static void |
184 | timeoverrun(int signo __unused) | |
1815bff5 A |
185 | { |
186 | ||
34d340d7 | 187 | syslog(LOG_ERR, "getty exiting due to excessive running time"); |
1815bff5 A |
188 | exit(1); |
189 | } | |
190 | ||
1815bff5 | 191 | int |
34d340d7 | 192 | main(int argc, char *argv[]) |
1815bff5 | 193 | { |
34d340d7 A |
194 | extern char **environ; |
195 | int first_sleep = 1, first_time = 1; | |
1815bff5 | 196 | struct rlimit limit; |
34d340d7 A |
197 | int rval; |
198 | #ifdef __APPLE__ | |
199 | int ttyopenmode = O_RDWR; | |
200 | #endif | |
1815bff5 A |
201 | |
202 | signal(SIGINT, SIG_IGN); | |
34d340d7 A |
203 | signal(SIGQUIT, SIG_IGN); |
204 | ||
205 | openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); | |
206 | gethostname(hostname, sizeof(hostname) - 1); | |
207 | hostname[sizeof(hostname) - 1] = '\0'; | |
1815bff5 A |
208 | if (hostname[0] == '\0') |
209 | strcpy(hostname, "Amnesiac"); | |
1815bff5 A |
210 | |
211 | /* | |
212 | * Limit running time to deal with broken or dead lines. | |
213 | */ | |
214 | (void)signal(SIGXCPU, timeoverrun); | |
215 | limit.rlim_max = RLIM_INFINITY; | |
216 | limit.rlim_cur = GETTY_TIMEOUT; | |
217 | (void)setrlimit(RLIMIT_CPU, &limit); | |
218 | ||
ef8ad44b | 219 | gettable("default"); |
34d340d7 A |
220 | gendefaults(); |
221 | tname = "default"; | |
222 | if (argc > 1) | |
223 | tname = argv[1]; | |
224 | ||
1815bff5 A |
225 | /* |
226 | * The following is a work around for vhangup interactions | |
227 | * which cause great problems getting window systems started. | |
228 | * If the tty line is "-", we do the old style getty presuming | |
34d340d7 | 229 | * that the file descriptors are already set up for us. |
1815bff5 A |
230 | * J. Gettys - MIT Project Athena. |
231 | */ | |
232 | if (argc <= 2 || strcmp(argv[2], "-") == 0) | |
34d340d7 A |
233 | #ifdef __APPLE__ |
234 | { | |
235 | // <rdar://problem/5178373> | |
236 | char* n = ttyname(STDIN_FILENO); | |
237 | if (n) { | |
238 | strlcpy(ttyn, n, sizeof(ttyn)); | |
239 | } else { | |
240 | syslog(LOG_ERR, "ttyname %m"); | |
241 | exit(1); | |
242 | } | |
243 | } | |
244 | #else | |
245 | strcpy(ttyn, ttyname(STDIN_FILENO)); | |
246 | #endif | |
1815bff5 | 247 | else { |
1815bff5 A |
248 | strcpy(ttyn, dev); |
249 | strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); | |
250 | if (strcmp(argv[0], "+") != 0) { | |
251 | chown(ttyn, 0, 0); | |
252 | chmod(ttyn, 0600); | |
253 | revoke(ttyn); | |
34d340d7 A |
254 | |
255 | /* | |
256 | * Do the first scan through gettytab. | |
257 | * Terminal mode parameters will be wrong until | |
258 | * defttymode() called, but they're irrelevant for | |
259 | * the initial setup of the terminal device. | |
260 | */ | |
261 | dogettytab(); | |
262 | ||
263 | #if defined(__APPLE__) && !TARGET_OS_EMBEDDED | |
264 | if (strncmp(ttyn, _PATH_CONSOLE, sizeof(ttyn)) == 0) | |
265 | ttyopenmode |= O_POPUP; | |
266 | #endif | |
1815bff5 | 267 | /* |
34d340d7 | 268 | * Init or answer modem sequence has been specified. |
1815bff5 | 269 | */ |
34d340d7 | 270 | if (IC || AC) { |
1815bff5 | 271 | #ifdef __APPLE__ |
34d340d7 A |
272 | if (!opentty(ttyn, ttyopenmode)) |
273 | #else | |
274 | if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) | |
275 | #endif | |
276 | exit(1); | |
277 | defttymode(); | |
278 | setttymode(1); | |
279 | } | |
280 | ||
281 | if (IC) { | |
282 | if (getty_chat(IC, CT, DC) > 0) { | |
283 | syslog(LOG_ERR, "modem init problem on %s", ttyn); | |
284 | (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); | |
285 | exit(1); | |
1815bff5 | 286 | } |
1815bff5 | 287 | } |
1815bff5 | 288 | |
34d340d7 A |
289 | if (AC) { |
290 | int i, rfds; | |
291 | struct timeval to; | |
292 | ||
cf37c299 A |
293 | rfds = 1 << 0; /* FD_SET */ |
294 | to.tv_sec = RT; | |
295 | to.tv_usec = 0; | |
296 | i = select(32, (fd_set*)&rfds, (fd_set*)NULL, | |
297 | (fd_set*)NULL, RT ? &to : NULL); | |
298 | if (i < 0) { | |
34d340d7 A |
299 | syslog(LOG_ERR, "select %s: %m", ttyn); |
300 | } else if (i == 0) { | |
301 | syslog(LOG_NOTICE, "recycle tty %s", ttyn); | |
302 | (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); | |
303 | exit(0); /* recycle for init */ | |
304 | } | |
305 | i = getty_chat(AC, CT, DC); | |
306 | if (i > 0) { | |
307 | syslog(LOG_ERR, "modem answer problem on %s", ttyn); | |
308 | (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); | |
309 | exit(1); | |
310 | } | |
311 | } else { /* maybe blocking open */ | |
312 | #ifdef __APPLE__ | |
313 | if (!opentty(ttyn, ttyopenmode | (NC ? O_NONBLOCK : 0 ))) | |
314 | #else | |
315 | if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 ))) | |
316 | #endif | |
317 | exit(1); | |
318 | } | |
319 | } | |
1815bff5 | 320 | } |
1815bff5 | 321 | |
34d340d7 | 322 | defttymode(); |
1815bff5 | 323 | for (;;) { |
34d340d7 A |
324 | |
325 | /* | |
cf37c299 | 326 | * if a delay was specified then sleep for that |
34d340d7 A |
327 | * number of seconds before writing the initial prompt |
328 | */ | |
329 | if (first_sleep && DE) { | |
330 | sleep(DE); | |
331 | /* remove any noise */ | |
332 | (void)tcflush(STDIN_FILENO, TCIOFLUSH); | |
1815bff5 | 333 | } |
34d340d7 | 334 | first_sleep = 0; |
1815bff5 | 335 | |
34d340d7 A |
336 | setttymode(0); |
337 | if (AB) { | |
1815bff5 | 338 | tname = autobaud(); |
34d340d7 | 339 | dogettytab(); |
1815bff5 A |
340 | continue; |
341 | } | |
342 | if (PS) { | |
343 | tname = portselector(); | |
34d340d7 | 344 | dogettytab(); |
1815bff5 A |
345 | continue; |
346 | } | |
347 | if (CL && *CL) | |
348 | putpad(CL); | |
349 | edithost(HE); | |
34d340d7 A |
350 | |
351 | /* if this is the first time through this, and an | |
352 | issue file has been given, then send it */ | |
353 | if (first_time && IF) { | |
354 | int fd; | |
355 | ||
356 | if ((fd = open(IF, O_RDONLY)) != -1) { | |
357 | char * cp; | |
358 | ||
fc6d9e4b | 359 | while ((cp = getty_getline(fd)) != NULL) { |
34d340d7 A |
360 | putf(cp); |
361 | } | |
362 | close(fd); | |
363 | } | |
364 | } | |
365 | first_time = 0; | |
366 | ||
367 | if (IM && *IM && !(PL && PP)) | |
1815bff5 A |
368 | putf(IM); |
369 | if (setjmp(timeout)) { | |
34d340d7 A |
370 | cfsetispeed(&tmode, B0); |
371 | cfsetospeed(&tmode, B0); | |
372 | (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); | |
1815bff5 A |
373 | exit(1); |
374 | } | |
375 | if (TO) { | |
376 | signal(SIGALRM, dingdong); | |
377 | alarm(TO); | |
378 | } | |
34d340d7 A |
379 | |
380 | rval = 0; | |
381 | if (AL) { | |
382 | const char *p = AL; | |
383 | char *q = name; | |
384 | ||
385 | while (*p && q < &name[sizeof name - 1]) { | |
386 | if (isupper(*p)) | |
387 | upper = 1; | |
388 | else if (islower(*p)) | |
389 | lower = 1; | |
390 | else if (isdigit(*p)) | |
391 | digit = 1; | |
392 | *q++ = *p++; | |
393 | } | |
394 | } else if (!(PL && PP)) | |
395 | rval = getname(); | |
396 | if (rval == 2 || (PL && PP)) { | |
397 | oflush(); | |
398 | alarm(0); | |
399 | limit.rlim_max = RLIM_INFINITY; | |
400 | limit.rlim_cur = RLIM_INFINITY; | |
401 | (void)setrlimit(RLIMIT_CPU, &limit); | |
402 | execle(PP, "ppplogin", ttyn, (char *) 0, env); | |
403 | syslog(LOG_ERR, "%s: %m", PP); | |
404 | exit(1); | |
405 | } else if (rval || AL) { | |
406 | int i; | |
1815bff5 A |
407 | |
408 | oflush(); | |
409 | alarm(0); | |
410 | signal(SIGALRM, SIG_DFL); | |
34d340d7 A |
411 | if (name[0] == '\0') |
412 | continue; | |
1815bff5 A |
413 | if (name[0] == '-') { |
414 | puts("user names may not start with '-'."); | |
415 | continue; | |
416 | } | |
34d340d7 A |
417 | if (!(upper || lower || digit)) { |
418 | if (AL) { | |
419 | syslog(LOG_ERR, | |
420 | "invalid auto-login name: %s", AL); | |
421 | exit(1); | |
422 | } else | |
423 | continue; | |
424 | } | |
425 | set_flags(2); | |
1815bff5 A |
426 | if (crmod) { |
427 | tmode.c_iflag |= ICRNL; | |
428 | tmode.c_oflag |= ONLCR; | |
429 | } | |
34d340d7 | 430 | #if REALLY_OLD_TTYS |
1815bff5 A |
431 | if (upper || UC) |
432 | tmode.sg_flags |= LCASE; | |
433 | if (lower || LC) | |
434 | tmode.sg_flags &= ~LCASE; | |
435 | #endif | |
34d340d7 A |
436 | if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { |
437 | syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); | |
1815bff5 A |
438 | exit(1); |
439 | } | |
440 | signal(SIGINT, SIG_DFL); | |
441 | for (i = 0; environ[i] != (char *)0; i++) | |
442 | env[i] = environ[i]; | |
443 | makeenv(&env[i]); | |
444 | ||
445 | limit.rlim_max = RLIM_INFINITY; | |
446 | limit.rlim_cur = RLIM_INFINITY; | |
447 | (void)setrlimit(RLIMIT_CPU, &limit); | |
34d340d7 A |
448 | #ifdef __APPLE__ |
449 | // <rdar://problem/3205179> | |
450 | execle(LO, "login", AL ? "-fp1" : "-p1", name, | |
451 | #else | |
452 | execle(LO, "login", AL ? "-fp" : "-p", name, | |
453 | #endif | |
454 | (char *) 0, env); | |
1815bff5 A |
455 | syslog(LOG_ERR, "%s: %m", LO); |
456 | exit(1); | |
457 | } | |
458 | alarm(0); | |
459 | signal(SIGALRM, SIG_DFL); | |
460 | signal(SIGINT, SIG_IGN); | |
34d340d7 | 461 | if (NX && *NX) { |
1815bff5 | 462 | tname = NX; |
34d340d7 A |
463 | dogettytab(); |
464 | } | |
465 | } | |
466 | } | |
467 | ||
468 | static int | |
469 | opentty(const char *tty, int flags) | |
470 | { | |
471 | int i; | |
472 | int failopenlogged = 0; | |
473 | ||
474 | while ((i = open(tty, flags)) == -1) | |
475 | { | |
476 | if (!failopenlogged) { | |
477 | syslog(LOG_ERR, "open %s: %m", tty); | |
478 | failopenlogged = 1; | |
479 | } | |
480 | sleep(60); | |
481 | } | |
cf37c299 | 482 | if (login_tty(i) < 0) { |
34d340d7 A |
483 | #ifndef __APPLE__ |
484 | if (daemon(0,0) < 0) { | |
485 | syslog(LOG_ERR,"daemon: %m"); | |
486 | close(i); | |
487 | return 0; | |
488 | } | |
489 | #endif | |
490 | if (login_tty(i) < 0) { | |
491 | syslog(LOG_ERR, "login_tty %s: %m", tty); | |
492 | close(i); | |
493 | return 0; | |
494 | } | |
495 | } | |
496 | return 1; | |
497 | } | |
498 | ||
499 | static void | |
cf37c299 | 500 | defttymode(void) |
34d340d7 A |
501 | { |
502 | ||
503 | /* Start with default tty settings. */ | |
504 | if (tcgetattr(STDIN_FILENO, &tmode) < 0) { | |
505 | syslog(LOG_ERR, "tcgetattr %s: %m", ttyn); | |
506 | exit(1); | |
507 | } | |
508 | omode = tmode; /* fill c_cc for dogettytab() */ | |
509 | dogettytab(); | |
510 | /* | |
511 | * Don't rely on the driver too much, and initialize crucial | |
512 | * things according to <sys/ttydefaults.h>. Avoid clobbering | |
513 | * the c_cc[] settings however, the console drivers might wish | |
514 | * to leave their idea of the preferred VERASE key value | |
515 | * there. | |
516 | */ | |
517 | tmode.c_iflag = TTYDEF_IFLAG; | |
518 | tmode.c_oflag = TTYDEF_OFLAG; | |
519 | tmode.c_lflag = TTYDEF_LFLAG; | |
520 | tmode.c_cflag = TTYDEF_CFLAG; | |
521 | if (NC) | |
522 | tmode.c_cflag |= CLOCAL; | |
523 | omode = tmode; | |
524 | } | |
525 | ||
526 | static void | |
527 | setttymode(int raw) | |
528 | { | |
529 | int off = 0; | |
530 | ||
531 | (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */ | |
532 | ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */ | |
533 | ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */ | |
534 | ||
535 | if (IS) | |
536 | cfsetispeed(&tmode, speed(IS)); | |
537 | else if (SP) | |
538 | cfsetispeed(&tmode, speed(SP)); | |
539 | if (OS) | |
540 | cfsetospeed(&tmode, speed(OS)); | |
541 | else if (SP) | |
542 | cfsetospeed(&tmode, speed(SP)); | |
543 | set_flags(0); | |
544 | setchars(); | |
545 | if (raw) | |
546 | cfmakeraw(&tmode); | |
547 | if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { | |
548 | syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); | |
549 | exit(1); | |
1815bff5 A |
550 | } |
551 | } | |
552 | ||
34d340d7 | 553 | |
1815bff5 | 554 | static int |
34d340d7 | 555 | getname(void) |
1815bff5 | 556 | { |
34d340d7 A |
557 | int c; |
558 | char *np; | |
559 | unsigned char cs; | |
560 | int ppp_state = 0; | |
561 | int ppp_connection = 0; | |
1815bff5 A |
562 | |
563 | /* | |
564 | * Interrupt may happen if we use CBREAK mode | |
565 | */ | |
566 | if (setjmp(intrupt)) { | |
567 | signal(SIGINT, SIG_IGN); | |
568 | return (0); | |
569 | } | |
570 | signal(SIGINT, interrupt); | |
34d340d7 | 571 | set_flags(1); |
1815bff5 | 572 | prompt(); |
34d340d7 | 573 | oflush(); |
1815bff5 | 574 | if (PF > 0) { |
1815bff5 A |
575 | sleep(PF); |
576 | PF = 0; | |
577 | } | |
34d340d7 | 578 | if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { |
1815bff5 A |
579 | syslog(LOG_ERR, "%s: %m", ttyn); |
580 | exit(1); | |
581 | } | |
582 | crmod = digit = lower = upper = 0; | |
583 | np = name; | |
584 | for (;;) { | |
585 | oflush(); | |
586 | if (read(STDIN_FILENO, &cs, 1) <= 0) | |
587 | exit(0); | |
588 | if ((c = cs&0177) == 0) | |
589 | return (0); | |
34d340d7 A |
590 | |
591 | /* PPP detection state machine.. | |
592 | Look for sequences: | |
593 | PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or | |
594 | PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) | |
595 | See RFC1662. | |
596 | Derived from code from Michael Hancock, <michaelh@cet.co.jp> | |
597 | and Erik 'PPP' Olson, <eriko@wrq.com> | |
598 | */ | |
599 | ||
600 | if (PP && (cs == PPP_FRAME)) { | |
601 | ppp_state = 1; | |
602 | } else if (ppp_state == 1 && cs == PPP_STATION) { | |
603 | ppp_state = 2; | |
604 | } else if (ppp_state == 2 && cs == PPP_ESCAPE) { | |
605 | ppp_state = 3; | |
606 | } else if ((ppp_state == 2 && cs == PPP_CONTROL) | |
607 | || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { | |
608 | ppp_state = 4; | |
609 | } else if (ppp_state == 4 && cs == PPP_LCP_HI) { | |
610 | ppp_state = 5; | |
611 | } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { | |
612 | ppp_connection = 1; | |
613 | break; | |
614 | } else { | |
615 | ppp_state = 0; | |
616 | } | |
617 | ||
618 | if (c == EOT || c == CTRL('d')) | |
619 | exit(0); | |
2fc1e207 | 620 | if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) { |
1815bff5 A |
621 | putf("\r\n"); |
622 | break; | |
623 | } | |
624 | if (islower(c)) | |
625 | lower = 1; | |
626 | else if (isupper(c)) | |
627 | upper = 1; | |
34d340d7 | 628 | else if (c == ERASE || c == '\b' || c == 0177) { |
1815bff5 A |
629 | if (np > name) { |
630 | np--; | |
631 | if (cfgetospeed(&tmode) >= 1200) | |
632 | puts("\b \b"); | |
633 | else | |
634 | putchr(cs); | |
635 | } | |
636 | continue; | |
34d340d7 | 637 | } else if (c == KILL || c == CTRL('u')) { |
1815bff5 A |
638 | putchr('\r'); |
639 | if (cfgetospeed(&tmode) < 1200) | |
640 | putchr('\n'); | |
641 | /* this is the way they do it down under ... */ | |
642 | else if (np > name) | |
643 | puts(" \r"); | |
644 | prompt(); | |
34d340d7 | 645 | digit = lower = upper = 0; |
1815bff5 A |
646 | np = name; |
647 | continue; | |
648 | } else if (isdigit(c)) | |
34d340d7 | 649 | digit = 1; |
1815bff5 A |
650 | if (IG && (c <= ' ' || c > 0176)) |
651 | continue; | |
652 | *np++ = c; | |
653 | putchr(cs); | |
654 | } | |
655 | signal(SIGINT, SIG_IGN); | |
656 | *np = 0; | |
657 | if (c == '\r') | |
658 | crmod = 1; | |
34d340d7 | 659 | if ((upper && !lower && !LC) || UC) |
1815bff5 A |
660 | for (np = name; *np; np++) |
661 | if (isupper(*np)) | |
662 | *np = tolower(*np); | |
34d340d7 | 663 | return (1 + ppp_connection); |
1815bff5 A |
664 | } |
665 | ||
666 | static void | |
34d340d7 | 667 | putpad(const char *s) |
1815bff5 | 668 | { |
34d340d7 | 669 | int pad = 0; |
1815bff5 A |
670 | speed_t ospeed = cfgetospeed(&tmode); |
671 | ||
672 | if (isdigit(*s)) { | |
673 | while (isdigit(*s)) { | |
674 | pad *= 10; | |
675 | pad += *s++ - '0'; | |
676 | } | |
677 | pad *= 10; | |
678 | if (*s == '.' && isdigit(s[1])) { | |
679 | pad += s[1] - '0'; | |
680 | s += 2; | |
681 | } | |
682 | } | |
683 | ||
684 | puts(s); | |
685 | /* | |
686 | * If no delay needed, or output speed is | |
687 | * not comprehensible, then don't try to delay. | |
688 | */ | |
689 | if (pad == 0 || ospeed <= 0) | |
690 | return; | |
691 | ||
692 | /* | |
693 | * Round up by a half a character frame, and then do the delay. | |
694 | * Too bad there are no user program accessible programmed delays. | |
695 | * Transmitting pad characters slows many terminals down and also | |
696 | * loads the system. | |
697 | */ | |
698 | pad = (pad * ospeed + 50000) / 100000; | |
699 | while (pad--) | |
700 | putchr(*PC); | |
701 | } | |
702 | ||
703 | static void | |
34d340d7 | 704 | puts(const char *s) |
1815bff5 A |
705 | { |
706 | while (*s) | |
707 | putchr(*s++); | |
708 | } | |
709 | ||
710 | char outbuf[OBUFSIZ]; | |
711 | int obufcnt = 0; | |
712 | ||
713 | static void | |
34d340d7 | 714 | putchr(int cc) |
1815bff5 A |
715 | { |
716 | char c; | |
717 | ||
718 | c = cc; | |
719 | if (!NP) { | |
720 | c |= partab[c&0177] & 0200; | |
721 | if (OP) | |
722 | c ^= 0200; | |
723 | } | |
724 | if (!UB) { | |
725 | outbuf[obufcnt++] = c; | |
726 | if (obufcnt >= OBUFSIZ) | |
727 | oflush(); | |
728 | } else | |
729 | write(STDOUT_FILENO, &c, 1); | |
730 | } | |
731 | ||
732 | static void | |
34d340d7 | 733 | oflush(void) |
1815bff5 A |
734 | { |
735 | if (obufcnt) | |
736 | write(STDOUT_FILENO, outbuf, obufcnt); | |
737 | obufcnt = 0; | |
738 | } | |
739 | ||
740 | static void | |
34d340d7 | 741 | prompt(void) |
1815bff5 A |
742 | { |
743 | ||
744 | putf(LM); | |
745 | if (CO) | |
746 | putchr('\n'); | |
747 | } | |
748 | ||
34d340d7 A |
749 | |
750 | static char * | |
fc6d9e4b | 751 | getty_getline(int fd) |
34d340d7 A |
752 | { |
753 | int i = 0; | |
754 | static char linebuf[512]; | |
755 | ||
756 | /* | |
757 | * This is certainly slow, but it avoids having to include | |
758 | * stdio.h unnecessarily. Issue files should be small anyway. | |
759 | */ | |
760 | while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) { | |
761 | if (linebuf[i] == '\n') { | |
762 | /* Don't rely on newline mode, assume raw */ | |
763 | linebuf[i++] = '\r'; | |
764 | linebuf[i++] = '\n'; | |
765 | linebuf[i] = '\0'; | |
766 | return linebuf; | |
767 | } | |
768 | ++i; | |
769 | } | |
770 | linebuf[i] = '\0'; | |
771 | return i ? linebuf : 0; | |
772 | } | |
773 | ||
1815bff5 | 774 | static void |
34d340d7 | 775 | putf(const char *cp) |
1815bff5 A |
776 | { |
777 | extern char editedhost[]; | |
778 | time_t t; | |
779 | char *slash, db[100]; | |
780 | ||
34d340d7 A |
781 | static struct utsname kerninfo; |
782 | ||
783 | if (!*kerninfo.sysname) | |
784 | uname(&kerninfo); | |
785 | ||
1815bff5 A |
786 | while (*cp) { |
787 | if (*cp != '%') { | |
788 | putchr(*cp++); | |
789 | continue; | |
790 | } | |
791 | switch (*++cp) { | |
792 | ||
793 | case 't': | |
794 | slash = strrchr(ttyn, '/'); | |
795 | if (slash == (char *) 0) | |
796 | puts(ttyn); | |
797 | else | |
798 | puts(&slash[1]); | |
799 | break; | |
800 | ||
801 | case 'h': | |
802 | puts(editedhost); | |
803 | break; | |
804 | ||
805 | case 'd': { | |
34d340d7 | 806 | t = (time_t)0; |
1815bff5 | 807 | (void)time(&t); |
34d340d7 A |
808 | if (Lo) |
809 | (void)setlocale(LC_TIME, Lo); | |
810 | (void)strftime(db, sizeof(db), DF, localtime(&t)); | |
1815bff5 A |
811 | puts(db); |
812 | break; | |
813 | ||
814 | case 's': | |
815 | puts(kerninfo.sysname); | |
816 | break; | |
817 | ||
818 | case 'm': | |
819 | puts(kerninfo.machine); | |
820 | break; | |
821 | ||
822 | case 'r': | |
823 | puts(kerninfo.release); | |
824 | break; | |
825 | ||
826 | case 'v': | |
827 | puts(kerninfo.version); | |
828 | break; | |
829 | } | |
830 | ||
831 | case '%': | |
832 | putchr('%'); | |
833 | break; | |
834 | } | |
835 | cp++; | |
836 | } | |
837 | } | |
34d340d7 A |
838 | |
839 | /* | |
840 | * Read a gettytab database entry and perform necessary quirks. | |
841 | */ | |
842 | static void | |
843 | dogettytab() | |
844 | { | |
34d340d7 | 845 | /* Read the database entry. */ |
ef8ad44b | 846 | gettable(tname); |
34d340d7 A |
847 | |
848 | /* | |
849 | * Avoid inheriting the parity values from the default entry | |
850 | * if any of them is set in the current entry. | |
851 | * Mixing different parity settings is unreasonable. | |
852 | */ | |
853 | if (OPset || EPset || APset || NPset) | |
854 | OPset = EPset = APset = NPset = 1; | |
855 | ||
856 | /* Fill in default values for unset capabilities. */ | |
857 | setdefaults(); | |
858 | } |