home *** CD-ROM | disk | FTP | other *** search
- /*
- * getty.c - main code
- * Part of getty(8) for MiNT by Dave Gymer
- * Copyright (C) 1991 D P Gymer. All rights reserved.
- * $Id: getty.c,v 0.1 1992/01/08 15:58:56 dpg Exp dpg $
- * $Log: getty.c,v $
- * Revision 0.1 1992/01/08 15:58:56 dpg
- * Added select(2) call (at least temporarily) so that lines on which this
- * call works will not tie up CPU time.
- * Added support for environmental changes. Still need to add the `ev'
- * capability.
- *
- * Revision 0.0 1991/11/24 19:43:44 dpg
- * First experimental version.
- *
- */
-
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <ioctl.h>
- #include <sgtty.h>
- #include <signal.h>
- #include <stat.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <termcap.h>
- #include <time.h>
- #include <unistd.h>
-
- #define GETTYTAB "/etc/gettytab"
- #ifndef LOGIN
- #define LOGIN "/usr/bin/login"
- #endif
-
- extern int putenv(char *);
- extern char **environ;
-
- #ifdef atarist
- int __default_mode__ = 1; /* All binary streams, please. */
- #endif
-
- struct gettytab {
- struct tchars gt_tchars;
- struct ltchars gt_ltchars;
- struct sgttyb gt_sgttyb;
- char prompt[32];
- char banner[80];
- char hostname[32];
- char login[FILENAME_MAX];
- char next[32];
- };
-
- /* In case we get signalled, eg. alarm. */
- static struct sgttyb save_sgttyb;
-
- /*
- * This isn't terribly efficient, but then it doesn't have to be, since
- * getty is only here until someone logs on.
- */
-
- static int
- my_putenv(char *string)
- {
- if (!(string = strdup(string)))
- perror("getty: malloc");
- else
- putenv(string);
- }
-
- /*
- * Take the current hostname and the hostname editing string and
- * produce a new hostname.
- */
-
- static void
- hostname_edit(char *hostname, const char *edit)
- {
- char oldname[32],
- *name;
-
- strcpy((name = oldname), hostname);
- do {
- switch (*edit) {
- case '@': /* Add a character. */
- if (*name)
- *hostname++ = *name++;
- break;
- case '#': /* Skip a character. */
- if (*name)
- ++name;
- break;
- default: /* Includes the null terminator. */
- *hostname++ = *edit;
- }
- } while (*edit++);
- }
-
- /*
- * Deal with the entry, setting the table entries as required.
- */
-
- static void
- deal_with_entry(char *entbuf, struct gettytab *buf)
- {
- char sbuf[128],
- termvar[64],
- *s = sbuf;
- int n;
-
- if (tgetstr("nx", &s))
- strcpy(buf -> next, (s = sbuf));
- else
- *buf -> next = '\0';
- if (tgetstr("hn", &s))
- strcpy(buf -> hostname, (s = sbuf));
- if (tgetstr("he", &s))
- hostname_edit(buf -> hostname, (s = sbuf));
- if (tgetstr("lm", &s))
- strcpy(buf -> prompt, (s = sbuf));
- if (tgetstr("lo", &s))
- strcpy(buf -> login, (s = sbuf));
- if (tgetstr("im", &s))
- strcpy(buf -> banner, (s = sbuf));
- if ((n = tgetnum("to")) != -1)
- alarm(n);
- if (tgetstr("tt", &s)) {
- sprintf(termvar, "TERM=%s", (s = sbuf));
- my_putenv(termvar);
- }
- }
-
- /*
- * Get a termcap entry from a named file.
- */
-
- static int
- tgetent_other(char *entbuf, char *type, const char *file)
- {
- extern char **environ;
- char **oldenv = environ,
- envbuf[128],
- *tmpenv[] = {envbuf, 0},
- retval;
-
- sprintf(envbuf, "TERMCAP=%s", file);
- environ = tmpenv;
- retval = tgetent(entbuf, type);
- environ = oldenv;
- return retval;
- }
-
- /*
- * Find the entry for a particular type and store it in buf.
- * If no entry is found, use some defaults.
- */
-
- static void
- get_getttytab(char *type, struct gettytab *buf)
- {
- char entbuf[2048];
-
- switch (tgetent_other(entbuf, type, GETTYTAB)) {
- case -1:
- case 0:
- sprintf(entbuf, "getty: non-existant type `%s'\r\n",
- type);
- write(0, entbuf, strlen(entbuf));
- break;
- default:
- deal_with_entry(entbuf, buf);
- }
- }
-
- /*
- * Format a string.
- * This consists mainly of substituting for %h and the like.
- * BUGS
- * - doesn't check for the end of the string buffer
- */
-
- static char *
- fmtstring(const char *s, const struct gettytab *tab)
- {
- static char buf[128];
- char *bp = buf;
-
- while (*s)
- if (*s == '%') {
- switch (*++s) {
- case '\0':
- goto out;
- case 'h':
- strcpy(bp, tab -> hostname);
- while (*bp)
- ++bp;
- break;
- case 't':
- strcpy(bp, ttyname(0));
- while (*bp)
- ++bp;
- break;
- default:
- *bp = *s;
- }
- ++s;
- } else
- *bp++ = *s++;
- out:
- *bp = '\0';
- return buf;
- }
-
- /*
- * Read the login name.
- * If break is pressed (or what we think is probably break), we try to
- * go to the next entry, by returning zero.
- */
-
- static int
- read_name(char *name, struct gettytab *buf, int canselect)
- {
- char *s,
- c;
- long fds = 1;
- struct sgttyb tmpsg = buf -> gt_sgttyb;
- extern long select(int, long *, long *, long *, struct timeval *);
-
- tmpsg.sg_flags |= RAW;
- tmpsg.sg_flags &= ~(ECHO | CRMOD);
- stty(0, &tmpsg);
-
- s = fmtstring(buf -> prompt, buf);
- write(0, s, strlen(s));
-
- s = name;
-
- if (canselect)
- select(1, &fds, 0, 0, 0);
- while (read(0, &c, 1) == 1 && c != '\n' && c != '\r') {
- if (!c || c & 128 || c == (buf -> gt_tchars).t_brkc)
- return 0;
- else if (c == (buf -> gt_sgttyb).sg_erase) {
- if (s > name) {
- --s;
- write(0, &(buf -> gt_sgttyb).sg_erase, 1);
- write(0, " ", 1);
- write(0, &(buf -> gt_sgttyb).sg_erase, 1);
- }
- } else {
- write(0, &c, 1);
- *s++ = c;
- }
- }
-
- /* Did we end with \n or \r? If the latter, we want EOL mapping. */
- if (c == '\n')
- (buf -> gt_sgttyb).sg_flags &= ~CRMOD;
- else
- (buf -> gt_sgttyb).sg_flags |= CRMOD;
-
- *s = '\0';
- write(0, "\r\n", 2);
-
- /* Did the name contain any lowercase letters? Assume not. */
- s = name;
- (buf -> gt_sgttyb).sg_flags &= ~LCASE;
- do
- if (islower(*s)) {
- (buf -> gt_sgttyb).sg_flags |= LCASE;
- break;
- }
- while (*s++);
-
- return 1;
- }
-
- static void
- do_alarm(long sig)
- {
- const char *s = "Connection timed out.\r\n";
-
- ioctl(0, TIOCSETP, &save_sgttyb);
- write(0, s, strlen(s));
- exit(1);
- }
-
- int
- main(int argc, char **argv)
- {
- struct gettytab tab;
- char *type = 0,
- *tty,
- buf[256];
- int fd,
- canselect,
- banner_flag = 1;
- struct stat info;
- extern int gethostname(char *, int);
- extern int execle(const char *, const char *,...);
- extern char *ttyname(int);
-
- ioctl(0, TIOCGETP, &save_sgttyb);
- signal(SIGALRM, do_alarm);
-
- /* Check for arguments. We ignore all but the last two. */
- if (argc > 2) { /* a tty was specified */
- close(0);
- fd = open((tty = argv[--argc]), O_RDWR);
- if (fd) {
- dup2(fd, 0);
- close(fd);
- fd = 0;
- }
- } else
- tty = ttyname(fd = 0);
-
- if (argc > 1) /* a type was specified */
- type = argv[--argc];
-
- if (fd < -1 || fd > 2)
- close(fd);
-
- #ifdef atarist
- dup2(fd, -1); /* Controlling terminal. */
- #endif
- dup2(fd, 1);
- dup2(fd, 2);
-
- /* Set up some defaults for the terminal type. */
- ioctl(0, TIOCGETP, &tab.gt_sgttyb);
- ioctl(0, TIOCGETC, &tab.gt_tchars);
- ioctl(0, TIOCGLTC, &tab.gt_ltchars);
- strcpy(tab.prompt, "login: ");
- strcpy(tab.banner, "%h running MiNT: line %t");
- strcpy(tab.login, LOGIN);
- *tab.next = '\0';
- gethostname(tab.hostname, 32);
-
- /* Get any default entries in the table. */
- get_getttytab("default", &tab);
-
- /* Fselect(2) does not yet work on BIOS devices except the console. */
- /* Probably when this works right, we won't need select anyway!!! */
- if (!strcmp("/dev/console", tty) ||
- !fstat(0, &info) && info.st_mode & S_IFMT != S_IFCHR)
- canselect = 1;
- else
- canselect = 0;
-
- /* Set up terminal type and read name until happy. */
- for (;;) {
- if (type && *type) { /* Type to look up? */
- get_getttytab(type, &tab);
- ioctl(0, TIOCSETP, &tab.gt_sgttyb);
- ioctl(0, TIOCSETC, &tab.gt_tchars);
- ioctl(0, TIOCSLTC, &tab.gt_ltchars);
- }
- if (banner_flag) { /* Print the banner? */
- char *s;
-
- s = fmtstring(tab.banner, &tab);
- write(0, s, strlen(s));
- banner_flag = 0;
- }
- if (!read_name(buf, &tab, canselect)) { /* Try next entry. */
- if (tab.next)
- type = tab.next;
- else
- type = 0;
- banner_flag = 1;
- } else if (*buf)/* Got a name. */
- break;
- }
- ioctl(0, TIOCSETP, &tab.gt_sgttyb); /* May have changed some. */
-
- /* Call login. If LOGIN is in use, preserve $TERM. */
- if (strcmp(LOGIN, tab.login))
- execle(tab.login, tab.login, buf, (char *) 0, environ);
- else
- execle(tab.login, tab.login, "-p", buf, (char *) 0, environ);
- sprintf(buf, "getty: can't exec (%s) - %s\r\n", tab.login,
- errno > 0 && errno <= sys_nerr ? strerror(errno) : "???");
- write(0, buf, strlen(buf));
- return 1;
- }
-