allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (12/15/89)
Posting-number: Volume 9, Issue 65
Submitted-by: wietse@wzv.win.tue.nl (Wietse Z. Venema)
Archive-name: agetty
This is a SYSV getty replacement that adapts itself to parity bits and
to erase, kill and end-of-line characters when a user enters her login
name. It has an optional facility do detect the baud rate of incoming
calls from the status messages produced by some multi-speed Hayes(tm)
modem clones.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: README agetty.c agetty.8 Makefile
# Wrapped by wietse@wzv on Wed Dec 13 00:22:33 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(490 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X@(#) README 1.1 11/26/89 22:04:59
X
XThis is a SYSV getty replacement that adapts itself to parity bits, and
Xto erase, kill and end-of-line characters found in its input. It also
Xhas an optional facility do detect the baud rate of incoming calls from
Xthe status messages produced by some multi-speed Hayes modem clones.
XThis program is an adapted version of a getty I once wrote for a V7 UNIX
Ximplementation; it does not use the /etc/gettydefs file.
X
X Wietse Venema (wietse@wzv.win.tue.nl)
END_OF_FILE
if test 490 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'agetty.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'agetty.c'\"
else
echo shar: Extracting \"'agetty.c'\" \(20261 characters\)
sed "s/^X//" >'agetty.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/* agetty 8
X/* SUMMARY
X/* alternative System-V getty
X/* SYNOPSIS
X/* agetty [-a alternate_rates] [-h] [-m] [-t timeout] port baud_rate
X/* DESCRIPTION
X/* \fIagetty\fR opens a tty port, prompts for a login name and invokes the
X/* /bin/login command. It is normally invoked by \fIinit(8)\fR.
X/*
X/* \fIagetty\fR has some useful features not present in the System
X/* V Release 2 getty command:
X/* .IP o
X/* Adapts the tty settings to parity bits and to
X/* erase, kill and end-of-line characters found in its input. The
X/* program understands 7-bit characters with even, odd, none or space
X/* parity, and 8-bit characters with no parity. The following special
X/* characters are recognized: @ and Control-U (kill); #, DEL and
X/* backspace (erase); carriage-return and linefeed (end of line).
X/* .IP o
X/* Optionally recognizes the baud rate of incoming
X/* calls from the status messages produced by some multi-speed Hayes (tm)
X/* modem clones.
X/* .PP
X/* This program does not use the \fI/etc/gettydefs\fR file. Except for
X/* differences described here the program appears to operate similar
X/* to the System-V Release 2 \fIgetty\fR program.
X/*
X/* Options:
X/* .TP
X/* -a alternate_rates
X/* Initially the program will use the \fIbaud_rate\fR as specified.
X/* Upon receipt of successive BREAK characters the program will step
X/* through the \fIalternate_rates\fR, which should be specified as a
X/* comma-separated list (preferably in decreasing order). After all
X/* \fIalternate_rates\fR have been tried, \fIagetty\fR will try the
X/* speed specified with the \fIbaud_rate\fR argument and so on.
X/* .TP
X/* -h
X/* Do not hang up the line. Normally, \fIagetty\fR will lower
X/* DTR for two seconds to force a modem to hang up (if the hangup
X/* feature has been compiled into the program).
X/* .TP
X/* -m
X/* Try to extract the baud rate of incoming calls from the status message
X/* produced by some Hayes (tm) multi-speed modem clones. These usually
X/* produce a status message of the form: "<junk><speed><junk>".
X/* If no \fIspeed\fR is found within one second, the \fIbaud_rate\fR as
X/* specified on the command line will be used. Since this feature will
X/* work only on lightly-loaded systems, you will probably want to use this
X/* feature in combination with the \fI-a\fR option.
X/* .TP
X/* -t timeout
X/* Causes the program to terminate if no user name could be read
X/* within \fItimeout\fR seconds. This is useful only for dial-in lines.
X/* EXAMPLES
X/* For hard-wired lines:
X/* .ti +5
X/* /etc/agetty ttyM0 9600
X/*
X/* For dial-in lines with a 300/1200/2400 baud Hayes clone:
X/* .ti +5
X/* /etc/agetty -t60 -m -a1200,300 ttyM1 2400
X/* FILES
X/* /etc/utmp, the system log file.
X/* BUGS
X/* The baud-rate detection code (the \fI-m\fR option) only works if
X/* \fIagetty\fR is scheduled soon enough after completion of a dial-in
X/* call (within 30 ms with modems that talk at 2400 baud). For robustness,
X/* always use the \fI-m\fR option in combination with the \fI-a\fR option.
X/*
X/* The login prompt is always output with space parity.
X/* DIAGNOSTICS
X/* All diagnostics are written to the console.
X/*
X/* In particular, \fIagetty\fR will detect if it is asked to open
X/* someting that is not a terminal.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* wietse@wzv.win.tue.nl
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Sat Nov 25 22:51:05 MET 1989
X/* LAST MODIFICATION
X/* 89/12/11 23:02:55
X/* VERSION/RELEASE
X/* 1.20
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) agetty.c 1.20 12/11/89 23:02:55";
X#endif
X
X#include <stdio.h>
X#include <termio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <varargs.h>
X#include <ctype.h>
X#include <utmp.h>
X
X /*
X * Things you may want to modify. HANGUP should be defined only if your tty
X * driver is not capable of hanging up the modem (by briefly dropping DTR).
X * If HANGUP is defined you probably cannot use the auto-baud and time-out
X * features.
X */
X
X#define LOGIN "\r\nlogin: " /* login prompt */
X
X/* #define HANGUP /* enable hangup code */
X
X/* Some shorthands for control characters */
X
X#define CTL(x) (x ^ 0100) /* controllify */
X#define CR CTL('M') /* carriage return */
X#define NL CTL('J') /* linefeed */
X#define BS CTL('H') /* backspace */
X#define DEL CTL('?') /* delete */
X
X/* Default values of special characters; you may want to change this */
X
X#define DEF_INTR CTL('C') /* default interrupt character */
X#define DEF_QUIT CTL('\\') /* default quit character */
X#define DEF_KILL CTL('U') /* default kill character */
X#define DEF_EOF CTL('D') /* default EOF character */
X#define DEF_SWITCH CTL('^') /* default switch character */
X#define DEF_ERASE BS /* default erase character */
X#define DEF_EOL 0
X
X/* Storage for command-line options */
X
X#define MAXSPEED 10
X
Xstruct options {
X int autobaud; /* process modem status messages */
X int timeout; /* timeout period */
X int hangup; /* hang up tty */
X int numspeed; /* number of baud rates to try */
X int curspeed; /* current speed */
X int speeds[MAXSPEED]; /* baud rates to be tried */
X char *tty; /* name of tty */
X};
X
X/* Storage for things detected while the login name was read */
X
Xstruct chardata {
X int erase; /* erase character */
X int kill; /* kill character */
X int eol; /* end-of-line character */
X int parity; /* what parity did we see */
X int capslock; /* upper case without lower case */
X};
X
X/* The following is used for understandable diagnostics */
X
Xextern int errno;
Xextern char *sys_errlist[];
Xstatic char *progname;
Xextern char *strcpy();
Xextern char *strcat();
X
X/* ... */
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X char *logname; /* login name, given to /bin/login */
X char *get_logname();
X struct chardata chardata; /* set by get_logname() */
X struct termio termio; /* terminal mode bits */
X static struct options options = {
X 0, /* no modem status message processing */
X 0, /* no timeout */
X 1, /* do hangup */
X 1, /* no baud-rate cycling */
X 0, /* use baud-rate argument as speed */
X };
X
X progname = argv[0];
X
X /* Parse command-line arguments */
X
X parse_args(argc, argv, &options);
X
X /* Update the utmp file */
X
X update_utmp(options.tty);
X
X /* Open the tty as standard { input, output, error } */
X
X open_tty(options.tty, &termio);
X
X /* Optionally hang up the tty */
X
X if (options.hangup)
X hangup_tty(&termio);
X
X /* Initialize the termio settings (raw mode, eight-bit, blocking i/o) */
X
X termio_init(&termio, options.speeds[0]);
X
X /* Optionally detect the baud rate from the modem status message */
X
X if (options.autobaud)
X auto_baud(&termio);
X
X /* With dial-in lines, briefly pause to allow modems etc. to settle */
X
X if (options.timeout)
X (void) sleep(1);
X
X /* Optional time-out feature */
X
X if (options.timeout)
X (void) alarm((unsigned) options.timeout);
X
X /* Read the login name */
X
X while ((logname = get_logname(&options, &chardata)) == 0)
X next_speed(&termio, &options);
X
X /* Disable time-out feature */
X
X if (options.timeout)
X (void) alarm(0);
X
X /* Finalize the termio settings */
X
X termio_final(&termio, &chardata);
X
X /* Now the newline should be properly output */
X
X (void) write(1, "\n", 1);
X
X /* Let /bin/login take care of password validation */
X
X execl("/bin/login", "login", logname, (char *) 0);
X error("%s: can't exec /bin/login", options.tty);
X /* NOTREACHED */
X}
X
X/* parse-args - parse command-line arguments */
X
Xparse_args(argc, argv, op)
Xint argc;
Xchar **argv;
Xstruct options *op;
X{
X extern char *optarg; /* getopt */
X extern int optind; /* getopt */
X int c;
X
X while ((c = getopt(argc, argv, "a:hmt:")) != EOF) {
X switch (c) {
X case 'a': /* enable auto-baud feature */
X parse_speeds(op, optarg);
X break;
X case 'h': /* do not hangup the tty */
X op->hangup = 0;
X break;
X case 'm': /* parse modem status message */
X op->autobaud = 1;
X break;
X case 't': /* time out */
X if ((op->timeout = atoi(optarg)) <= 0)
X error("bad timeout value: %s", optarg);
X break;
X case '?':
X usage();
X }
X }
X if (argc != optind + 2) /* check parameter count */
X usage();
X op->tty = argv[optind++]; /* tty name */
X if ((op->speeds[0] = bcode(argv[optind])) <= 0) /* baud rate */
X error("bad speed: %s", argv[optind]);
X}
X
X/* parse_speeds - parse alternate baud rates */
X
Xparse_speeds(op, arg)
Xstruct options *op;
Xchar *arg;
X{
X char *strtok();
X char *cp;
X
X for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
X if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
X error("bad speed: %s", cp);
X if (op->numspeed > MAXSPEED)
X error("too many alternate speeds");
X }
X}
X
X/* update_utmp - update our utmp entry */
X
Xupdate_utmp(line)
Xchar *line;
X{
X struct utmp ut;
X long ut_size = sizeof(ut); /* avoid nonsense */
X int ut_fd;
X int mypid = getpid();
X long time();
X long lseek();
X
X /*
X * The utmp file holds miscellaneous information about things started by
X * /etc/init and other system-related events. Our purpose is to update
X * the utmp entry for the current process, in particular the process type
X * and the tty line we are listening to. Return successfully only if the
X * utmp file can be opened for update, and if we are able to find our
X * entry in the utmp file.
X */
X
X if ((ut_fd = open(UTMP_FILE, 2)) < 0) {
X error("%s: open for update", UTMP_FILE);
X } else {
X while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) {
X if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) {
X ut.ut_type = LOGIN_PROCESS;
X ut.ut_time = time((long *) 0);
X (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name));
X (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
X (void) lseek(ut_fd, -ut_size, 1);
X (void) write(ut_fd, (char *) &ut, sizeof(ut));
X (void) close(ut_fd);
X return;
X }
X }
X error("no utmp entry found for process id %u", mypid);
X }
X}
X
X/* open_tty - open tty as standard { input, output, error } */
X
Xopen_tty(tty, tp)
Xchar *tty;
Xstruct termio *tp;
X{
X struct stat st;
X
X /* Close standard { input, output, error } files, just in case */
X
X (void) close(0);
X (void) close(1);
X (void) close(2);
X errno = 0; /* ignore above errors */
X
X /* Make sure we are given a character device */
X
X if (chdir("/dev"))
X error("/dev: chdir() failed");
X if (stat(tty, &st) < 0)
X error("/dev/%s: stat() failed", tty);
X if ((st.st_mode & S_IFMT) != S_IFCHR)
X error("not a character device: /dev/%s", tty);
X
X /* Set up new standard input, output and error files */
X
X if (open(tty, 2) != 0) /* set up std input */
X error("/dev/%s: cannot open as standard input", tty);
X if (dup(0) != 1 || dup(0) != 2) /* set up std out and std err */
X error("%s: dup problem", tty); /* we have a problem */
X if (ioctl(0, TCGETA, tp) < 0) /* read tty status bits */
X error("%s: ioctl failed", tty); /* this is not a terminal */
X
X /* It seems to be a terminal; set proper protections and ownership */
X
X (void) chown(tty, 0, 0); /* root, sys */
X (void) chmod(tty, 0622); /* crw--w--w- */
X errno = 0; /* ignore above errors */
X}
X
X/* hangup_tty - hang up by forcing DTR down for at least 2 seconds */
X
Xhangup_tty(tp)
Xstruct termio *tp;
X{
X#ifdef HANGUP
X (void) signal(SIGHUP, SIG_IGN);
X tp->c_cflag &= ~CBAUD;
X tp->c_cflag |= B0;
X (void) ioctl(0, TCSETA, tp);
X (void) signal(SIGHUP, SIG_DFL);
X (void) sleep(2);
X#endif
X}
X
X/* termio_init - initialize termio settings */
X
Xtermio_init(tp, speed)
Xstruct termio *tp;
Xint speed;
X{
X
X /*
X * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
X * Special characters are set after we have read the login name; all
X * reads will be done in raw mode anyway.
X */
X
X tp->c_cflag = CS8 | HUPCL | CREAD | speed;
X tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0;
X tp->c_cc[VMIN] = 1;
X tp->c_cc[VTIME] = 0;
X (void) ioctl(0, TCSETA, tp);
X}
X
X/* auto_baud - extract baud rate from modem status message */
X
Xauto_baud(tp)
Xstruct termio *tp;
X{
X int speed;
X int vmin;
X int iflag;
X char buf[BUFSIZ];
X char *bp;
X int nread;
X
X /*
X * This works only if the modem produces its status code AFTER raising
X * the DCD line, and if the computer is fast enough to set the proper
X * baud rate before the message has gone by. We expect a message of the
X * following format:
X *
X * <junk><number><junk>
X *
X * The number is interpreted as the baud rate of the incoming call. If the
X * modem does not tell us the baud rate within one second we will keep
X * using the current baud rate. It is advisable to enable baud-rate
X * cycling (-a option) if the processing of modem status messages is
X * enabled.
X */
X
X /* Use 7-bit characters, don't block if input queue is empty */
X
X iflag = tp->c_iflag;
X tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
X vmin = tp->c_cc[VMIN];
X tp->c_cc[VMIN] = 0; /* don't block if queue empty */
X (void) ioctl(0, TCSETA, tp);
X
X /*
X * Wait for a while, then read everything the modem has said so far and
X * try to extract the speed of the dial-in call.
X */
X
X (void) sleep(1);
X if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
X buf[nread] = '\0';
X for (bp = buf; bp < buf + nread; bp++) {
X if (isascii(*bp) && isdigit(*bp)) {
X if (speed = bcode(bp)) {
X tp->c_cflag &= ~CBAUD;
X tp->c_cflag |= speed;
X }
X break;
X }
X }
X }
X /* Restore settings */
X
X tp->c_iflag = iflag;
X tp->c_cc[VMIN] = vmin;
X (void) ioctl(0, TCSETA, tp);
X}
X
X/* next_speed - select next baud rate */
X
Xnext_speed(tp, op)
Xstruct termio *tp;
Xstruct options *op;
X{
X op->curspeed = (op->curspeed + 1) % op->numspeed;
X tp->c_cflag &= ~CBAUD;
X tp->c_cflag |= op->speeds[op->curspeed];
X (void) ioctl(0, TCSETA, tp);
X}
X
X/* get_logname - get user name, establish parity, speed, erase, kill, eol */
X
Xchar *get_logname(op, cp)
Xstruct options *op;
Xstruct chardata *cp;
X{
X char logname[BUFSIZ];
X char *bp;
X char c; /* input character, full eight bits */
X char ascval; /* low 7 bits of input character */
X int bits; /* # of "1" bits per character */
X int mask; /* mask with 1 bit up */
X static char *erase[] = { /* backspace-space-backspace */
X "\010\040\010", /* space parity */
X "\010\040\010", /* odd parity */
X "\210\240\210", /* even parity */
X "\210\240\210", /* no parity */
X };
X
X /* Initialize kill, erase, parity etcetera (also after switching speeds) */
X
X cp->kill = DEF_KILL;
X cp->erase = DEF_ERASE;
X cp->parity = 0;
X
X /* Flush any pending input */
X
X ioctl(0, TCFLSH, (struct termio *) 0);
X
X /* Read a login name */
X
X for (*logname = 0; *logname == 0; /* void */ ) {
X
X /* Write the prompt, with "parity" bit == 0 */
X
X (void) write(1, LOGIN, sizeof(LOGIN) - 1);
X
X /* Read name, watch for break, parity, erase, kill, end-of-line */
X
X for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
X if (read(0, &c, 1) < 1)
X error("%s: read error", op->tty);
X
X /* Do BREAK handling elsewhere */
X
X if ((c == 0) && op->numspeed > 1)
X return (0);
X
X /* Do parity bit handling */
X
X if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */
X for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
X if (mask & ascval)
X bits++; /* count "1" bits */
X cp->parity |= ((bits & 1) ? 1 : 2);
X }
X /* Do erase, kill and end-of-line processing */
X
X switch (ascval) {
X case CR:
X case NL:
X *bp = 0; /* terminate logname */
X cp->eol = ascval; /* send end-of-line char */
X break;
X case BS:
X case DEL:
X case '#':
X cp->erase = ascval; /* set erase character */
X if (bp > logname) {
X (void) write(1, erase[cp->parity], 3);
X bp--;
X }
X break;
X case CTL('U'):
X case '@':
X cp->kill = ascval; /* set kill character */
X while (bp > logname) {
X (void) write(1, erase[cp->parity], 3);
X bp--;
X }
X break;
X case CTL('D'):
X exit(0);
X default:
X if (!isascii(ascval) || !isprint(ascval)) {
X /* ignore garbage characters */ ;
X } else if (bp - logname >= sizeof(logname) - 1) {
X error("%s: input overrun", op->tty);
X } else {
X (void) write(1, &c, 1); /* echo the character */
X *bp++ = ascval; /* and store it */
X }
X break;
X }
X }
X }
X cp->capslock = caps_lock(logname); /* upper case w/o lower case? */
X return (logname);
X}
X
X/* termio_final - set the final tty mode bits */
X
Xtermio_final(tp, cp)
Xstruct termio *tp;
Xstruct chardata *cp;
X{
X /* General terminal-independent stuff */
X
X tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */
X tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK;
X tp->c_oflag |= OPOST;
X tp->c_cc[VEOF] = DEF_EOF;
X tp->c_cc[VEOL] = DEF_EOL;
X tp->c_cc[VINTR] = DEF_INTR;
X tp->c_cc[VQUIT] = DEF_QUIT;
X tp->c_cc[VKILL] = DEF_KILL;
X tp->c_cc[VERASE] = DEF_ERASE;
X tp->c_cc[VSWTCH] = DEF_SWITCH;
X
X /* Account for special characters seen in input */
X
X if (cp->eol == CR) {
X tp->c_iflag |= ICRNL; /* map CR in input to NL */
X tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */
X }
X tp->c_cc[VERASE] = cp->erase; /* set erase character */
X tp->c_cc[VKILL] = cp->kill; /* set kill character */
X
X /* Account for the presence or absence of parity bits in input */
X
X switch (cp->parity) {
X case 0: /* space (always 0) parity */
X break;
X case 1: /* odd parity */
X tp->c_cflag |= PARODD;
X /* FALLTHROUGH */
X case 2: /* even parity */
X tp->c_cflag |= PARENB;
X tp->c_iflag |= INPCK | ISTRIP;
X /* FALLTHROUGH */
X case (1 | 2): /* no parity bit */
X tp->c_cflag &= ~CSIZE;
X tp->c_cflag |= CS7;
X break;
X }
X /* Account for upper case without lower case */
X
X if (cp->capslock) {
X tp->c_iflag |= IUCLC;
X tp->c_lflag |= XCASE;
X tp->c_oflag |= OLCUC;
X }
X
X /* Finally, make the new settings effective */
X
X (void) ioctl(0, TCSETA, tp);
X}
X
X/* caps_lock - string contains upper case without lower case */
X
Xcaps_lock(s)
Xchar *s;
X{
X int hascaps;
X
X for (hascaps = 0; *s; s++) {
X if (islower(*s))
X return (0);
X if (hascaps == 0)
X hascaps = isupper(*s);
X }
X return (hascaps);
X}
X
X/* bcode - convert speed string to speed code; return 0 on failure */
X
Xbcode(s)
Xchar *s;
X{
X struct Speedtab {
X int speed;
X int code;
X };
X static struct Speedtab speedtab[] = {
X 50, B50,
X 75, B75,
X 110, B110,
X 134, B134,
X 150, B150,
X 200, B200,
X 300, B300,
X 600, B600,
X 1200, B1200,
X 1800, B1800,
X 2400, B2400,
X 4800, B4800,
X 9600, B9600,
X 19200, EXTA,
X 0, 0,
X };
X struct Speedtab *sp;
X int speed = atoi(s);
X
X for (sp = speedtab; sp->speed; sp++)
X if (sp->speed == speed)
X return (sp->code);
X return (0);
X}
X
X/* usage - explain */
X
Xusage()
X{
X error("usage: %s [-a alternate_rates] [-h] [-m] [-t timeout] line baud_rate",
X progname);
X}
X
X/* error - report errors to the console; only understands %s */
X
X#define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
X
X/* VARARGS */
X
Xerror(va_alist)
Xva_dcl
X{
X va_list ap;
X char *fmt;
X int fd;
X int err = errno;
X char buf[BUFSIZ];
X char *bp;
X
X if ((fd = open("/dev/console", 1)) >= 0) {
X (void) str2cpy(buf, progname, ": ");
X bp = buf + strlen(buf);
X
X /*
X * %s expansion is done by hand. The program would become three times
X * as big if we would use the stdio library...
X */
X
X va_start(ap);
X fmt = va_arg(ap, char *);
X while (*fmt) {
X if (strncmp(fmt, "%s", 2) == 0) {
X (void) strcat(bp, va_arg(ap, char *));
X bp += strlen(bp);
X fmt += 2;
X } else {
X *bp++ = *fmt++;
X }
X }
X *bp = 0;
X va_end(ap);
X
X /* Add system error message if errno was set */
X
X if (err)
X (void) str2cpy(bp, ": ", sys_errlist[errno]);
X
X /* Terminate with CR-LF since the console mode is unknown */
X
X (void) strcat(bp, "\r\n");
X (void) write(fd, buf, strlen(buf));
X (void) close(fd);
X }
X (void) sleep(5); /* be kind to init */
X exit(1);
X}
X
END_OF_FILE
if test 20261 -ne `wc -c <'agetty.c'`; then
echo shar: \"'agetty.c'\" unpacked with wrong size!
fi
# end of 'agetty.c'
fi
if test -f 'agetty.8' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'agetty.8'\"
else
echo shar: Extracting \"'agetty.8'\" \(3388 characters\)
sed "s/^X//" >'agetty.8' <<'END_OF_FILE'
X.TH AGETTY 8
X.ad
X.fi
X.SH NAME
Xagetty
X\-
Xalternative System-V getty
X.SH SYNOPSIS
X.na
X.nf
Xagetty [-a alternate_rates] [-h] [-m] [-t timeout] port baud_rate
X.SH DESCRIPTION
X.ad
X.fi
X\fIagetty\fR opens a tty port, prompts for a login name and invokes the
X/bin/login command. It is normally invoked by \fIinit(8)\fR.
X
X\fIagetty\fR has some useful features not present in the System
XV Release 2 getty command:
X.IP o
XAdapts the tty settings to parity bits and to
Xerase, kill and end-of-line characters found in its input. The
Xprogram understands 7-bit characters with even, odd, none or space
Xparity, and 8-bit characters with no parity. The following special
Xcharacters are recognized: @ and Control-U (kill); #, DEL and
Xbackspace (erase); carriage-return and linefeed (end of line).
X.IP o
XOptionally recognizes the baud rate of incoming
Xcalls from the status messages produced by some multi-speed Hayes (tm)
Xmodem clones.
X.PP
XThis program does not use the \fI/etc/gettydefs\fR file. Except for
Xdifferences described here the program appears to operate similar
Xto the System-V Release 2 \fIgetty\fR program.
X
XOptions:
X.TP
X-a alternate_rates
XInitially the program will use the \fIbaud_rate\fR as specified.
XUpon receipt of successive BREAK characters the program will step
Xthrough the \fIalternate_rates\fR, which should be specified as a
Xcomma-separated list (preferably in decreasing order). After all
X\fIalternate_rates\fR have been tried, \fIagetty\fR will try the
Xspeed specified with the \fIbaud_rate\fR argument and so on.
X.TP
X-h
XDo not hang up the line. Normally, \fIagetty\fR will lower
XDTR for two seconds to force a modem to hang up (if the hangup
Xfeature has been compiled into the program).
X.TP
X-m
XTry to extract the baud rate of incoming calls from the status message
Xproduced by some Hayes (tm) multi-speed modem clones. These usually
Xproduce a status message of the form: "<junk><speed><junk>".
XIf no \fIspeed\fR is found within one second, the \fIbaud_rate\fR as
Xspecified on the command line will be used. Since this feature will
Xwork only on lightly-loaded systems, you will probably want to use this
Xfeature in combination with the \fI-a\fR option.
X.TP
X-t timeout
XCauses the program to terminate if no user name could be read
Xwithin \fItimeout\fR seconds. This is useful only for dial-in lines.
X.SH EXAMPLES
X.na
X.nf
XFor hard-wired lines:
X.ti +5
X/etc/agetty ttyM0 9600
X
XFor dial-in lines with a 300/1200/2400 baud Hayes clone:
X.ti +5
X/etc/agetty -t60 -m -a1200,300 ttyM1 2400
X.SH FILES
X.na
X.nf
X/etc/utmp, the system log file.
X.SH BUGS
X.ad
X.fi
XThe baud-rate detection code (the \fI-m\fR option) only works if
X\fIagetty\fR is scheduled soon enough after completion of a dial-in
Xcall (within 30 ms with modems that talk at 2400 baud). For robustness,
Xalways use the \fI-m\fR option in combination with the \fI-a\fR option.
X
XThe login prompt is always output with space parity.
X.SH DIAGNOSTICS
X.ad
X.fi
XAll diagnostics are written to the console.
X
XIn particular, \fIagetty\fR will detect if it is asked to open
Xsometing that is not a terminal.
X.SH AUTHOR(S)
X.na
X.nf
XW.Z. Venema
Xwietse@wzv.win.tue.nl
XEindhoven University of Technology
XDepartment of Mathematics and Computer Science
XDen Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X.SH CREATION DATE
X.na
X.nf
XSat Nov 25 22:51:05 MET 1989
X.SH LAST MODIFICATION
X.na
X.nf
X89/12/11 23:02:55
X.SH VERSION/RELEASE
X.na
X.nf
X1.20
END_OF_FILE
if test 3388 -ne `wc -c <'agetty.8'`; then
echo shar: \"'agetty.8'\" unpacked with wrong size!
fi
# end of 'agetty.8'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(257 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# @(#) Makefile 1.3 11/26/89 22:20:28
X
XSHELL = /bin/sh
XCFLAGS = -s -O
XFILES = README agetty.c agetty.8 Makefile
X
Xagetty: agetty.c
X cc $(CFLAGS) -o $@ $?
X
Xclean:
X rm -f agetty.o agetty
X
Xshar: $(FILES)
X @shar $(FILES)
X
Xagetty.8:
X srctoman agetty.c >agetty.8
END_OF_FILE
if test 257 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
echo shar: End of shell archive.
exit 0