From decwrl!purdue!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!usc!cs.utexas.edu!uunet!allbery Tue Jan 30 09:20:27 PST 1990 Article 1320 of comp.sources.misc: Path: decwrl!purdue!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!usc!cs.utexas.edu!uunet!allbery From: wietse@wzv.win.tue.nl (Wietse Z. Venema) Newsgroups: comp.sources.misc Subject: v10i050: agetty, SYSV getty for dial-in lines Keywords: agetty2 Message-ID: <77903@uunet.UU.NET> Date: 28 Jan 90 18:35:05 GMT Sender: allbery@uunet.UU.NET Organization: Eindhoven University of Technology, The Netherlands Lines: 1042 Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) Posting-number: Volume 10, Issue 50 Submitted-by: wietse@wzv.win.tue.nl (Wietse Z. Venema) Archive-name: agetty2 This is a SYSV getty replacement with useful features for dial-in lines. The program adjusts the tty modes to parity bits, and to erase, kill and end-of-line characters found while reading a login name. The baud rate of incoming calls can be established by BREAK character processing or by parsing status messages produced by multi-speed Hayes-compatible modems. The first release of this program appeared december 1989. The main new feature introduced here is selective processing of the /etc/issue file. #! /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 'README' <<'END_OF_FILE' X@(#) README 1.4 1/28/90 17:53:02 X XThis is a SYSV getty replacement with useful features for dial-in lines. X XThe program adjusts the tty modes to parity bits, and to erase, kill and Xend-of-line characters found while reading a login name. The baud rate Xof incoming calls can be established by BREAK character processing or by Xparsing status messages produced by multi-speed Hayes-compatible modems. X X Wietse Venema (wietse@wzv.win.tue.nl) END_OF_FILE if test 440 -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'\" \(22691 characters\) sed "s/^X//" >'agetty.c' <<'END_OF_FILE' X/*++ X/* NAME X/* agetty 8 X/* SUMMARY X/* alternative System-V getty for dial-up lines X/* SYNOPSIS X/* agetty [-a alternate_rates] [-h] [-i] [-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 for dial-up lines that are X/* not present in the System 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/* back space (erase); carriage return and line feed (end of line). X/* .IP o X/* Optionally recognizes the baud rate of incoming calls from the X/* status messages produced by some multi-speed Hayes-compatible modems. X/* .IP o X/* Optionally does not display the contents of the \fI/etc/issue\fR file. X/* .PP X/* This program does not use the \fI/etc/gettydefs\fR file. Except for X/* differences described in the documentation, the program appears to X/* operate similar 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/* -i X/* Do not display the contents of \fI/etc/issue\fR before writing the X/* login prompt. Terminals or computer programs may become confused X/* when receiving lots of text at the wrong baud rate; dial-up scripts X/* may fail if the login prompt is preceded by too much text. X/* .TP X/* -m X/* Try to extract the baud rate of incoming calls from the status message X/* produced by some multi-speed Hayes-compatible modems. These usually X/* produce a status message of the form: "". 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 the \fI-m\fR feature X/* will work only on lightly-loaded systems, you will probably want to use X/* it 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 multi-speed modem: X/* .ti +5 X/* /etc/agetty -t60 -m -a1200,300 ttyM1 2400 X/* FILES X/* /etc/utmp, the system log file. X/* /etc/issue, printed before the login prompt. X/* /dev/console, problem reports. 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 contents of the /etc/issue file and the login prompt are always X/* output with space parity. X/* DIAGNOSTICS X/* All diagnostics are written to the console device. Error messages are X/* produced if the \fIport\fR argument does not specify a terminal; if X/* there is no /etc/utmp entry for the current process; and so on. X/* AUTHOR(S) X/* W.Z. Venema 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/* 90/01/28 17:53:06 X/* VERSION/RELEASE X/* 1.26 X/*--*/ X X#ifndef lint Xstatic char sccsid[] = "@(#) agetty.c 1.26 1/28/90 17:53:06"; X#endif X X#include X#include X#include X#include X#include X#include X#include X X /* X * Things you may want to modify. X * X * HANGUP should be defined only if your tty driver is not able to hang up the X * modem (by briefly dropping DTR). If HANGUP is defined you probably cannot X * use the auto-baud and time-out features. X * X * If ISSUE is not defined, agetty will never display the contents of the X * /etc/issue file. You will not want to spit out large "issue" files at the X * wrong baud rate. X * X * You may disagree with the default line-editing etc. characters defined X * below. Note, however, that DEL cannot be used for interrupt generation X * and for line editing at the same time. X */ X X#define ISSUE "/etc/issue" /* shown before login prompt */ X X#define LOGIN "login: " /* login prompt */ X X/* #define HANGUP /* enable hangup code */ X X/* Some shorthands for control characters */ X X#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ X#define CR CTL('M') /* carriage return */ X#define NL CTL('J') /* line feed */ X#define BS CTL('H') /* back space */ X#define DEL CTL('?') /* delete */ X X/* Defaults for line-editing etc. characters; you may want to change this */ X X#define DEF_INTR CTL('C') /* default interrupt character */ X#define DEF_QUIT CTL('\\') /* default quit char */ X#define DEF_KILL CTL('U') /* default kill char */ X#define DEF_EOF CTL('D') /* default EOF char */ X#define DEF_SWITCH CTL('^') /* default switch char */ X#define DEF_ERASE BS /* default erase char, see below */ X#define DEF_EOL 0 X X /* X * This program does not need the standard-i/o library. This keeps the X * executable small; useful for systems that do not have shared libaries X * (Sys-V Rel <3). X */ X X#define BUFSIZ 1024 X X/* Storage for command-line options */ X X#define MAXSPEED 10 X Xstruct options { X int flags; /* toggle switches, see below */ X int timeout; /* time-out period */ 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#define F_PARSE (1<<0) /* process modem status messages */ X#define F_HANGUP (1<<1) /* hangup line */ X#define F_ISSUE (1<<2) /* display /etc/issue */ 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 F_HANGUP | F_ISSUE, /* hangup line and show /etc/issue */ X 0, /* no timeout */ X 1, /* no alternate baud rates */ X 0, /* no alternate baud rates */ 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.flags & F_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.flags & F_PARSE) 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, &termio)) == 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 character should be properly written */ X X (void) write(1, "\n", 1); X X /* Let /bin/login take care of password validation */ X X (void) 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 (isascii(c = getopt(argc, argv, "a:himt:"))) { 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->flags &= ~F_HANGUP; X break; X case 'i': /* do not show /etc/issue */ X op->flags &= ~F_ISSUE; X break; X case 'm': /* parse modem status message */ X op->flags |= F_PARSE; 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 char *strncpy(); 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#ifdef lint X#define HANGUP X#endif 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 * 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/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ X Xdo_prompt(op, tp) Xstruct options *op; Xstruct termio *tp; X{ X#ifdef ISSUE X int fd; X int oflag; X int n; X char buf[BUFSIZ]; X#endif X X write(1, "\r\n", 2); /* Start a new line */ X#ifdef ISSUE /* Optional: show /etc/issue */ X if ((op->flags & F_ISSUE) && (fd = open(ISSUE, 0)) >= 0) { X oflag = tp->c_oflag; /* Save current setting */ X tp->c_oflag |= (ONLCR | OPOST); /* Map NL in output to CR-NL */ X (void) ioctl(0, TCSETAW, tp); X while ((n = read(fd, buf, sizeof(buf))) > 0) X (void) write(1, buf, n); X tp->c_oflag = oflag; /* Restore settings */ X (void) ioctl(0, TCSETAW, tp); /* Wait till output gone */ X (void) close(fd); X } X#endif X (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* Always show login prompt */ 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, tp) Xstruct options *op; Xstruct chardata *cp; Xstruct termio *tp; 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 (void) ioctl(0, TCFLSH, (struct termio *) 0); X X /* Read a login name */ X X for (*logname = 0; *logname == 0; /* void */ ) { X X /* Write issue file and prompt, with "parity" bit == 0 */ X X do_prompt(op, tp); 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; /* set 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 /* 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 static char args[] = X "[-a alternate_rates] [-h] [-i] [-m] [-t timeout] line baud_rate"; X X error("usage: %s %s", progname, args); 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} END_OF_FILE if test 22691 -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'\" \(3984 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 for dial-up lines X.SH SYNOPSIS X.na X.nf Xagetty [-a alternate_rates] [-h] [-i] [-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 for dial-up lines that are Xnot present in the System V 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 Xback space (erase); carriage return and line feed (end of line). X.IP o XOptionally recognizes the baud rate of incoming calls from the Xstatus messages produced by some multi-speed Hayes-compatible modems. X.IP o XOptionally does not display the contents of the \fI/etc/issue\fR file. X.PP XThis program does not use the \fI/etc/gettydefs\fR file. Except for Xdifferences described in the documentation, the program appears to Xoperate similar to 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-i XDo not display the contents of \fI/etc/issue\fR before writing the Xlogin prompt. Terminals or computer programs may become confused Xwhen receiving lots of text at the wrong baud rate; dial-up scripts Xmay fail if the login prompt is preceded by too much text. X.TP X-m XTry to extract the baud rate of incoming calls from the status message Xproduced by some multi-speed Hayes-compatible modems. These usually Xproduce a status message of the form: "". XIf no \fIspeed\fR is found within one second, the \fIbaud_rate\fR as Xspecified on the command line will be used. Since the \fI-m\fR feature Xwill work only on lightly-loaded systems, you will probably want to use Xit 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 multi-speed modem: 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/etc/issue, printed before the login prompt. X/dev/console, problem reports. 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 contents of the /etc/issue file and the login prompt are always Xoutput with space parity. X.SH DIAGNOSTICS X.ad X.fi XAll diagnostics are written to the console device. Error messages are Xproduced if the \fIport\fR argument does not specify a terminal; if Xthere is no /etc/utmp entry for the current process; and so on. X.SH AUTHOR(S) X.na X.nf XW.Z. Venema 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 X90/01/28 17:53:06 X.SH VERSION/RELEASE X.na X.nf X1.26 END_OF_FILE if test 3984 -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