home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
mint
/
init_5
/
getty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
9KB
|
388 lines
/*
* 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;
}