main.c revision 1.5 1 /*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)main.c 5.16 (Berkeley) 3/27/91";*/
42 static char rcsid[] = "$Id: main.c,v 1.5 1994/03/09 04:59:59 cgd Exp $";
43 #endif /* not lint */
44
45 #define USE_OLD_TTY
46
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/utsname.h>
50 #include <signal.h>
51 #include <fcntl.h>
52 #include <sgtty.h>
53 #include <time.h>
54 #include <ctype.h>
55 #include <setjmp.h>
56 #include <syslog.h>
57 #include <unistd.h>
58 #include <ctype.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include "gettytab.h"
62 #include "pathnames.h"
63
64 struct sgttyb tmode = {
65 0, 0, CERASE, CKILL, 0
66 };
67 struct tchars tc = {
68 CINTR, CQUIT, CSTART,
69 CSTOP, CEOF, CBRK,
70 };
71 struct ltchars ltc = {
72 CSUSP, CDSUSP, CRPRNT,
73 CFLUSH, CWERASE, CLNEXT
74 };
75
76 int crmod, digit, lower, upper;
77
78 char hostname[MAXHOSTNAMELEN];
79 struct utsname kerninfo;
80 char name[16];
81 char dev[] = _PATH_DEV;
82 char ttyn[32];
83 char *portselector();
84 char *ttyname();
85
86 #define OBUFSIZ 128
87 #define TABBUFSIZ 512
88
89 char defent[TABBUFSIZ];
90 char tabent[TABBUFSIZ];
91
92 char *env[128];
93
94 char partab[] = {
95 0001,0201,0201,0001,0201,0001,0001,0201,
96 0202,0004,0003,0205,0005,0206,0201,0001,
97 0201,0001,0001,0201,0001,0201,0201,0001,
98 0001,0201,0201,0001,0201,0001,0001,0201,
99 0200,0000,0000,0200,0000,0200,0200,0000,
100 0000,0200,0200,0000,0200,0000,0000,0200,
101 0000,0200,0200,0000,0200,0000,0000,0200,
102 0200,0000,0000,0200,0000,0200,0200,0000,
103 0200,0000,0000,0200,0000,0200,0200,0000,
104 0000,0200,0200,0000,0200,0000,0000,0200,
105 0000,0200,0200,0000,0200,0000,0000,0200,
106 0200,0000,0000,0200,0000,0200,0200,0000,
107 0000,0200,0200,0000,0200,0000,0000,0200,
108 0200,0000,0000,0200,0000,0200,0200,0000,
109 0200,0000,0000,0200,0000,0200,0200,0000,
110 0000,0200,0200,0000,0200,0000,0000,0201
111 };
112
113 #define ERASE tmode.sg_erase
114 #define KILL tmode.sg_kill
115 #define EOT tc.t_eofc
116
117 jmp_buf timeout;
118
119 static void
120 dingdong()
121 {
122
123 alarm(0);
124 signal(SIGALRM, SIG_DFL);
125 longjmp(timeout, 1);
126 }
127
128 jmp_buf intrupt;
129
130 static void
131 interrupt()
132 {
133
134 signal(SIGINT, interrupt);
135 longjmp(intrupt, 1);
136 }
137
138 main(argc, argv)
139 int argc;
140 char **argv;
141 {
142 extern char **environ;
143 char *tname;
144 long allflags;
145 int repcnt = 0;
146
147 signal(SIGINT, SIG_IGN);
148 /*
149 signal(SIGQUIT, SIG_DFL);
150 */
151 openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
152 gethostname(hostname, sizeof(hostname));
153 if (hostname[0] == '\0')
154 strcpy(hostname, "Amnesiac");
155 uname(&kerninfo);
156 /*
157 * The following is a work around for vhangup interactions
158 * which cause great problems getting window systems started.
159 * If the tty line is "-", we do the old style getty presuming
160 * that the file descriptors are already set up for us.
161 * J. Gettys - MIT Project Athena.
162 */
163 if (argc <= 2 || strcmp(argv[2], "-") == 0)
164 strcpy(ttyn, ttyname(0));
165 else {
166 int i;
167
168 strcpy(ttyn, dev);
169 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
170 if (strcmp(argv[0], "+") != 0) {
171 chown(ttyn, 0, 0);
172 chmod(ttyn, 0600);
173 revoke(ttyn);
174 /*
175 * Delay the open so DTR stays down long enough to be detected.
176 */
177 sleep(2);
178 while ((i = open(ttyn, O_RDWR)) == -1) {
179 if (repcnt % 10 == 0) {
180 syslog(LOG_ERR, "%s: %m", ttyn);
181 closelog();
182 }
183 repcnt++;
184 sleep(60);
185 }
186 login_tty(i);
187 }
188 }
189
190 gettable("default", defent);
191 gendefaults();
192 tname = "default";
193 if (argc > 1)
194 tname = argv[1];
195 for (;;) {
196 int ldisp = OTTYDISC;
197 int off = 0;
198
199 gettable(tname, tabent);
200 if (OPset || EPset || APset)
201 APset++, OPset++, EPset++;
202 setdefaults();
203 ioctl(0, TIOCFLUSH, 0); /* clear out the crap */
204 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
205 ioctl(0, FIOASYNC, &off); /* ditto for async mode */
206 if (IS)
207 tmode.sg_ispeed = speed(IS);
208 else if (SP)
209 tmode.sg_ispeed = speed(SP);
210 if (OS)
211 tmode.sg_ospeed = speed(OS);
212 else if (SP)
213 tmode.sg_ospeed = speed(SP);
214 tmode.sg_flags = setflags(0);
215 ioctl(0, TIOCSETP, &tmode);
216 setchars();
217 ioctl(0, TIOCSETC, &tc);
218 if (HC)
219 ioctl(0, TIOCHPCL, 0);
220 if (AB) {
221 extern char *autobaud();
222
223 tname = autobaud();
224 continue;
225 }
226 if (PS) {
227 tname = portselector();
228 continue;
229 }
230 if (CL && *CL)
231 putpad(CL);
232 edithost(HE);
233 if (IM && *IM)
234 putf(IM);
235 if (setjmp(timeout)) {
236 tmode.sg_ispeed = tmode.sg_ospeed = 0;
237 ioctl(0, TIOCSETP, &tmode);
238 exit(1);
239 }
240 if (TO) {
241 signal(SIGALRM, dingdong);
242 alarm(TO);
243 }
244 if (getname()) {
245 register int i;
246
247 oflush();
248 alarm(0);
249 signal(SIGALRM, SIG_DFL);
250 if (name[0] == '-') {
251 puts("user names may not start with '-'.");
252 continue;
253 }
254 if (!(upper || lower || digit))
255 continue;
256 allflags = setflags(2);
257 tmode.sg_flags = allflags & 0xffff;
258 allflags >>= 16;
259 if (crmod || NL)
260 tmode.sg_flags |= CRMOD;
261 if (upper || UC)
262 tmode.sg_flags |= LCASE;
263 if (lower || LC)
264 tmode.sg_flags &= ~LCASE;
265 ioctl(0, TIOCSETP, &tmode);
266 ioctl(0, TIOCSLTC, <c);
267 ioctl(0, TIOCLSET, &allflags);
268 signal(SIGINT, SIG_DFL);
269 for (i = 0; environ[i] != (char *)0; i++)
270 env[i] = environ[i];
271 makeenv(&env[i]);
272 execle(LO, "login", "-p", name, (char *) 0, env);
273 syslog(LOG_ERR, "%s: %m", LO);
274 exit(1);
275 }
276 alarm(0);
277 signal(SIGALRM, SIG_DFL);
278 signal(SIGINT, SIG_IGN);
279 if (NX && *NX)
280 tname = NX;
281 }
282 }
283
284 getname()
285 {
286 register int c;
287 register char *np;
288 char cs;
289
290 /*
291 * Interrupt may happen if we use CBREAK mode
292 */
293 if (setjmp(intrupt)) {
294 signal(SIGINT, SIG_IGN);
295 return (0);
296 }
297 signal(SIGINT, interrupt);
298 tmode.sg_flags = setflags(0);
299 ioctl(0, TIOCSETP, &tmode);
300 tmode.sg_flags = setflags(1);
301 prompt();
302 if (PF > 0) {
303 oflush();
304 sleep(PF);
305 PF = 0;
306 }
307 ioctl(0, TIOCSETP, &tmode);
308 crmod = digit = lower = upper = 0;
309 np = name;
310 for (;;) {
311 oflush();
312 if (read(STDIN_FILENO, &cs, 1) <= 0)
313 exit(0);
314 if ((c = cs&0177) == 0)
315 return (0);
316 if (c == EOT)
317 exit(1);
318 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
319 putf("\r\n");
320 break;
321 }
322 if (islower(c))
323 lower = 1;
324 else if (isupper(c))
325 upper = 1;
326 else if (c == ERASE || c == '#' || c == '\b') {
327 if (np > name) {
328 np--;
329 if (tmode.sg_ospeed >= B1200)
330 puts("\b \b");
331 else
332 putchr(cs);
333 }
334 continue;
335 } else if (c == KILL || c == '@') {
336 putchr(cs);
337 putchr('\r');
338 if (tmode.sg_ospeed < B1200)
339 putchr('\n');
340 /* this is the way they do it down under ... */
341 else if (np > name)
342 puts(" \r");
343 prompt();
344 np = name;
345 continue;
346 } else if (isdigit(c))
347 digit++;
348 if (IG && (c <= ' ' || c > 0176))
349 continue;
350 *np++ = c;
351 putchr(cs);
352 }
353 signal(SIGINT, SIG_IGN);
354 *np = 0;
355 if (c == '\r')
356 crmod = 1;
357 if (upper && !lower && !LC || UC)
358 for (np = name; *np; np++)
359 if (isupper(*np))
360 *np = tolower(*np);
361 return (1);
362 }
363
364 static
365 short tmspc10[] = {
366 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
367 };
368
369 putpad(s)
370 register char *s;
371 {
372 register pad = 0;
373 register mspc10;
374
375 if (isdigit(*s)) {
376 while (isdigit(*s)) {
377 pad *= 10;
378 pad += *s++ - '0';
379 }
380 pad *= 10;
381 if (*s == '.' && isdigit(s[1])) {
382 pad += s[1] - '0';
383 s += 2;
384 }
385 }
386
387 puts(s);
388 /*
389 * If no delay needed, or output speed is
390 * not comprehensible, then don't try to delay.
391 */
392 if (pad == 0)
393 return;
394 if (tmode.sg_ospeed <= 0 ||
395 tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
396 return;
397
398 /*
399 * Round up by a half a character frame, and then do the delay.
400 * Too bad there are no user program accessible programmed delays.
401 * Transmitting pad characters slows many terminals down and also
402 * loads the system.
403 */
404 mspc10 = tmspc10[tmode.sg_ospeed];
405 pad += mspc10 / 2;
406 for (pad /= mspc10; pad > 0; pad--)
407 putchr(*PC);
408 }
409
410 puts(s)
411 register char *s;
412 {
413 while (*s)
414 putchr(*s++);
415 }
416
417 char outbuf[OBUFSIZ];
418 int obufcnt = 0;
419
420 putchr(cc)
421 {
422 char c;
423
424 c = cc;
425 if (!NP) {
426 c |= partab[c&0177] & 0200;
427 if (OP)
428 c ^= 0200;
429 }
430 if (!UB) {
431 outbuf[obufcnt++] = c;
432 if (obufcnt >= OBUFSIZ)
433 oflush();
434 } else
435 write(STDOUT_FILENO, &c, 1);
436 }
437
438 oflush()
439 {
440 if (obufcnt)
441 write(STDOUT_FILENO, outbuf, obufcnt);
442 obufcnt = 0;
443 }
444
445 prompt()
446 {
447
448 putf(LM);
449 if (CO)
450 putchr('\n');
451 }
452
453 putf(cp)
454 register char *cp;
455 {
456 extern char editedhost[];
457 time_t t;
458 char *slash, db[100];
459
460 while (*cp) {
461 if (*cp != '%') {
462 putchr(*cp++);
463 continue;
464 }
465 switch (*++cp) {
466
467 case 't':
468 slash = rindex(ttyn, '/');
469 if (slash == (char *) 0)
470 puts(ttyn);
471 else
472 puts(&slash[1]);
473 break;
474
475 case 'h':
476 puts(editedhost);
477 break;
478
479 case 'd': {
480 static char fmt[] = "%l:% %P on %A, %d %B %Y";
481
482 fmt[4] = 'M'; /* I *hate* SCCS... */
483 (void)time(&t);
484 (void)strftime(db, sizeof(db), fmt, localtime(&t));
485 puts(db);
486 break;
487
488 case 's':
489 puts(kerninfo.sysname);
490 break;
491
492 case 'm':
493 puts(kerninfo.machine);
494 break;
495
496 case 'r':
497 puts(kerninfo.release);
498 break;
499
500 case 'v':
501 puts(kerninfo.version);
502 break;
503 }
504
505 case '%':
506 putchr('%');
507 break;
508 }
509 cp++;
510 }
511 }
512