]> git.saurik.com Git - apple/system_cmds.git/blob - getty.tproj/main.c
cafc07dd18d7d84ac52d3d01ba40684aee847b83
[apple/system_cmds.git] / getty.tproj / main.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*-
26 * Copyright (c) 1980, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 #ifndef lint
59 static char copyright[] =
60 "@(#) Copyright (c) 1980, 1993\n\
61 The Regents of the University of California. All rights reserved.\n";
62 #endif /* not lint */
63
64 #ifndef lint
65 /*static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";*/
66 static char rcsid[] = "$Id: main.c,v 1.1.1.2 2000/01/11 02:10:14 wsanchez Exp $";
67 #endif /* not lint */
68
69 #include <sys/param.h>
70 #include <sys/stat.h>
71 #include <sys/termios.h>
72 #include <sys/ioctl.h>
73 #include <sys/resource.h>
74 #include <sys/utsname.h>
75 #include <signal.h>
76 #include <fcntl.h>
77 #include <time.h>
78 #include <ctype.h>
79 #include <fcntl.h>
80 #include <setjmp.h>
81 #include <signal.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <syslog.h>
85 #include <time.h>
86 #include <unistd.h>
87
88 #include "gettytab.h"
89 #include "pathnames.h"
90 #include "extern.h"
91
92 /*
93 * Set the amount of running time that getty should accumulate
94 * before deciding that something is wrong and exit.
95 */
96 #define GETTY_TIMEOUT 60 /* seconds */
97
98 struct termios tmode, omode;
99
100 int crmod, digit, lower, upper;
101
102 char hostname[MAXHOSTNAMELEN];
103 struct utsname kerninfo;
104 char name[16];
105 char dev[] = _PATH_DEV;
106 char ttyn[32];
107 char *portselector();
108 char *ttyname();
109
110 #define OBUFSIZ 128
111 #define TABBUFSIZ 512
112
113 char defent[TABBUFSIZ];
114 char tabent[TABBUFSIZ];
115
116 char *env[128];
117
118 char partab[] = {
119 0001,0201,0201,0001,0201,0001,0001,0201,
120 0202,0004,0003,0205,0005,0206,0201,0001,
121 0201,0001,0001,0201,0001,0201,0201,0001,
122 0001,0201,0201,0001,0201,0001,0001,0201,
123 0200,0000,0000,0200,0000,0200,0200,0000,
124 0000,0200,0200,0000,0200,0000,0000,0200,
125 0000,0200,0200,0000,0200,0000,0000,0200,
126 0200,0000,0000,0200,0000,0200,0200,0000,
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 0000,0200,0200,0000,0200,0000,0000,0200,
132 0200,0000,0000,0200,0000,0200,0200,0000,
133 0200,0000,0000,0200,0000,0200,0200,0000,
134 0000,0200,0200,0000,0200,0000,0000,0201
135 };
136
137 #define ERASE tmode.c_cc[VERASE]
138 #define KILL tmode.c_cc[VKILL]
139 #define EOT tmode.c_cc[VEOF]
140
141 jmp_buf timeout;
142
143 static void
144 dingdong()
145 {
146
147 alarm(0);
148 signal(SIGALRM, SIG_DFL);
149 longjmp(timeout, 1);
150 }
151
152 jmp_buf intrupt;
153
154 static void
155 interrupt()
156 {
157
158 signal(SIGINT, interrupt);
159 longjmp(intrupt, 1);
160 }
161
162 /*
163 * Action to take when getty is running too long.
164 */
165 void
166 timeoverrun(signo)
167 int signo;
168 {
169
170 syslog(LOG_ERR, "getty exiting due to excessive running time\n");
171 exit(1);
172 }
173
174 static int getname __P((void));
175 static void oflush __P((void));
176 static void prompt __P((void));
177 static void putchr __P((int));
178 static void putf __P((char *));
179 static void putpad __P((char *));
180 static void puts __P((char *));
181
182 int
183 main(argc, argv)
184 int argc;
185 char *argv[];
186 {
187 extern char **environ;
188 char *tname;
189 long allflags;
190 int repcnt = 0;
191 struct rlimit limit;
192 int ttyopenmode;
193
194 signal(SIGINT, SIG_IGN);
195 /*
196 signal(SIGQUIT, SIG_DFL);
197 */
198 openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
199 gethostname(hostname, sizeof(hostname));
200 if (hostname[0] == '\0')
201 strcpy(hostname, "Amnesiac");
202 uname(&kerninfo);
203
204 /*
205 * Limit running time to deal with broken or dead lines.
206 */
207 (void)signal(SIGXCPU, timeoverrun);
208 limit.rlim_max = RLIM_INFINITY;
209 limit.rlim_cur = GETTY_TIMEOUT;
210 (void)setrlimit(RLIMIT_CPU, &limit);
211
212 /*
213 * The following is a work around for vhangup interactions
214 * which cause great problems getting window systems started.
215 * If the tty line is "-", we do the old style getty presuming
216 * that the file descriptors are already set up for us.
217 * J. Gettys - MIT Project Athena.
218 */
219 if (argc <= 2 || strcmp(argv[2], "-") == 0)
220 strcpy(ttyn, ttyname(0));
221 else {
222 int i;
223
224 strcpy(ttyn, dev);
225 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
226 if (strcmp(argv[0], "+") != 0) {
227 chown(ttyn, 0, 0);
228 chmod(ttyn, 0600);
229 revoke(ttyn);
230 /*
231 * Delay the open so DTR stays down long enough to be detected.
232 */
233 sleep(2);
234 #ifdef __APPLE__
235 ttyopenmode = ((strcmp(ttyn, _PATH_CONSOLE)==0)
236 ? (O_RDWR |O_POPUP): O_RDWR);
237 #else /* __APPLE __ */
238 ttyopenmode = O_RDWR;
239 #endif /* __APPLE__ */
240
241 while ((i = open(ttyn, ttyopenmode)) == -1) {
242 if (repcnt % 10 == 0) {
243 syslog(LOG_ERR, "%s: %m", ttyn);
244 closelog();
245 }
246 repcnt++;
247 sleep(60);
248 }
249 login_tty(i);
250 }
251 }
252
253 /* Start with default tty settings */
254 if (tcgetattr(0, &tmode) < 0) {
255 syslog(LOG_ERR, "%s: %m", ttyn);
256 exit(1);
257 }
258 omode = tmode;
259
260 gettable("default", defent);
261 gendefaults();
262 tname = "default";
263 if (argc > 1)
264 tname = argv[1];
265 for (;;) {
266 int off;
267
268 gettable(tname, tabent);
269 if (OPset || EPset || APset)
270 APset++, OPset++, EPset++;
271 setdefaults();
272 off = 0;
273 ioctl(0, TIOCFLUSH, &off); /* clear out the crap */
274 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
275 ioctl(0, FIOASYNC, &off); /* ditto for async mode */
276
277 if (IS)
278 cfsetispeed(&tmode, IS);
279 else if (SP)
280 cfsetispeed(&tmode, SP);
281 if (OS)
282 cfsetospeed(&tmode, OS);
283 else if (SP)
284 cfsetospeed(&tmode, SP);
285 setflags(0);
286 setchars();
287 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
288 syslog(LOG_ERR, "%s: %m", ttyn);
289 exit(1);
290 }
291 if (AB) {
292 extern char *autobaud();
293
294 tname = autobaud();
295 continue;
296 }
297 if (PS) {
298 tname = portselector();
299 continue;
300 }
301 if (CL && *CL)
302 putpad(CL);
303 edithost(HE);
304 if (IM && *IM)
305 putf(IM);
306 if (setjmp(timeout)) {
307 tmode.c_ispeed = tmode.c_ospeed = 0;
308 (void)tcsetattr(0, TCSANOW, &tmode);
309 exit(1);
310 }
311 if (TO) {
312 signal(SIGALRM, dingdong);
313 alarm(TO);
314 }
315 if (getname()) {
316 register int i;
317
318 oflush();
319 alarm(0);
320 signal(SIGALRM, SIG_DFL);
321 if (name[0] == '-') {
322 puts("user names may not start with '-'.");
323 continue;
324 }
325 if (!(upper || lower || digit))
326 continue;
327 setflags(2);
328 if (crmod) {
329 tmode.c_iflag |= ICRNL;
330 tmode.c_oflag |= ONLCR;
331 }
332 #if XXX
333 if (upper || UC)
334 tmode.sg_flags |= LCASE;
335 if (lower || LC)
336 tmode.sg_flags &= ~LCASE;
337 #endif
338 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
339 syslog(LOG_ERR, "%s: %m", ttyn);
340 exit(1);
341 }
342 signal(SIGINT, SIG_DFL);
343 for (i = 0; environ[i] != (char *)0; i++)
344 env[i] = environ[i];
345 makeenv(&env[i]);
346
347 limit.rlim_max = RLIM_INFINITY;
348 limit.rlim_cur = RLIM_INFINITY;
349 (void)setrlimit(RLIMIT_CPU, &limit);
350 execle(LO, "login", "-p", name, (char *) 0, env);
351 syslog(LOG_ERR, "%s: %m", LO);
352 exit(1);
353 }
354 alarm(0);
355 signal(SIGALRM, SIG_DFL);
356 signal(SIGINT, SIG_IGN);
357 if (NX && *NX)
358 tname = NX;
359 }
360 }
361
362 static int
363 getname()
364 {
365 register int c;
366 register char *np;
367 char cs;
368
369 /*
370 * Interrupt may happen if we use CBREAK mode
371 */
372 if (setjmp(intrupt)) {
373 signal(SIGINT, SIG_IGN);
374 return (0);
375 }
376 signal(SIGINT, interrupt);
377 setflags(1);
378 prompt();
379 if (PF > 0) {
380 oflush();
381 sleep(PF);
382 PF = 0;
383 }
384 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
385 syslog(LOG_ERR, "%s: %m", ttyn);
386 exit(1);
387 }
388 crmod = digit = lower = upper = 0;
389 np = name;
390 for (;;) {
391 oflush();
392 if (read(STDIN_FILENO, &cs, 1) <= 0)
393 exit(0);
394 if ((c = cs&0177) == 0)
395 return (0);
396 if (c == EOT)
397 exit(1);
398 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
399 putf("\r\n");
400 break;
401 }
402 if (islower(c))
403 lower = 1;
404 else if (isupper(c))
405 upper = 1;
406 else if (c == ERASE || c == '#' || c == '\b') {
407 if (np > name) {
408 np--;
409 if (cfgetospeed(&tmode) >= 1200)
410 puts("\b \b");
411 else
412 putchr(cs);
413 }
414 continue;
415 } else if (c == KILL || c == '@') {
416 putchr(cs);
417 putchr('\r');
418 if (cfgetospeed(&tmode) < 1200)
419 putchr('\n');
420 /* this is the way they do it down under ... */
421 else if (np > name)
422 puts(" \r");
423 prompt();
424 np = name;
425 continue;
426 } else if (isdigit(c))
427 digit++;
428 if (IG && (c <= ' ' || c > 0176))
429 continue;
430 *np++ = c;
431 putchr(cs);
432 }
433 signal(SIGINT, SIG_IGN);
434 *np = 0;
435 if (c == '\r')
436 crmod = 1;
437 if (upper && !lower && !LC || UC)
438 for (np = name; *np; np++)
439 if (isupper(*np))
440 *np = tolower(*np);
441 return (1);
442 }
443
444 static void
445 putpad(s)
446 register char *s;
447 {
448 register pad = 0;
449 speed_t ospeed = cfgetospeed(&tmode);
450
451 if (isdigit(*s)) {
452 while (isdigit(*s)) {
453 pad *= 10;
454 pad += *s++ - '0';
455 }
456 pad *= 10;
457 if (*s == '.' && isdigit(s[1])) {
458 pad += s[1] - '0';
459 s += 2;
460 }
461 }
462
463 puts(s);
464 /*
465 * If no delay needed, or output speed is
466 * not comprehensible, then don't try to delay.
467 */
468 if (pad == 0 || ospeed <= 0)
469 return;
470
471 /*
472 * Round up by a half a character frame, and then do the delay.
473 * Too bad there are no user program accessible programmed delays.
474 * Transmitting pad characters slows many terminals down and also
475 * loads the system.
476 */
477 pad = (pad * ospeed + 50000) / 100000;
478 while (pad--)
479 putchr(*PC);
480 }
481
482 static void
483 puts(s)
484 register char *s;
485 {
486 while (*s)
487 putchr(*s++);
488 }
489
490 char outbuf[OBUFSIZ];
491 int obufcnt = 0;
492
493 static void
494 putchr(cc)
495 int cc;
496 {
497 char c;
498
499 c = cc;
500 if (!NP) {
501 c |= partab[c&0177] & 0200;
502 if (OP)
503 c ^= 0200;
504 }
505 if (!UB) {
506 outbuf[obufcnt++] = c;
507 if (obufcnt >= OBUFSIZ)
508 oflush();
509 } else
510 write(STDOUT_FILENO, &c, 1);
511 }
512
513 static void
514 oflush()
515 {
516 if (obufcnt)
517 write(STDOUT_FILENO, outbuf, obufcnt);
518 obufcnt = 0;
519 }
520
521 static void
522 prompt()
523 {
524
525 putf(LM);
526 if (CO)
527 putchr('\n');
528 }
529
530 static void
531 putf(cp)
532 register char *cp;
533 {
534 extern char editedhost[];
535 time_t t;
536 char *slash, db[100];
537
538 while (*cp) {
539 if (*cp != '%') {
540 putchr(*cp++);
541 continue;
542 }
543 switch (*++cp) {
544
545 case 't':
546 slash = strrchr(ttyn, '/');
547 if (slash == (char *) 0)
548 puts(ttyn);
549 else
550 puts(&slash[1]);
551 break;
552
553 case 'h':
554 puts(editedhost);
555 break;
556
557 case 'd': {
558 static char fmt[] = "%l:% %P on %A, %d %B %Y";
559
560 fmt[4] = 'M'; /* I *hate* SCCS... */
561 (void)time(&t);
562 (void)strftime(db, sizeof(db), fmt, localtime(&t));
563 puts(db);
564 break;
565
566 case 's':
567 puts(kerninfo.sysname);
568 break;
569
570 case 'm':
571 puts(kerninfo.machine);
572 break;
573
574 case 'r':
575 puts(kerninfo.release);
576 break;
577
578 case 'v':
579 puts(kerninfo.version);
580 break;
581 }
582
583 case '%':
584 putchr('%');
585 break;
586 }
587 cp++;
588 }
589 }