Newsgroups: comp.sources.misc From: Wietse Venema Subject: v22i086: agetty - SysVR2/SunOS4 smart getty command, Part01/01 Message-ID: <1991Sep4.004838.13289@sparky.IMD.Sterling.COM> X-Md4-Signature: 37cd8595a8e0fc68cba103131c8834ee Date: Wed, 4 Sep 1991 00:48:38 GMT Approved: kent@sparky.imd.sterling.com Submitted-by: Wietse Venema Posting-number: Volume 22, Issue 86 Archive-name: agetty/part01 Environment: SYSVR2, SunOS 4.x Supersedes: agetty2: Volume 10, Issue 50 This is a SYSV/SunOS4 getty program with useful features for hardwired and dial-in tty lines. Previous versions that appeared in this news group were specific to the SYSV environment. - The program adapts the tty modes to parity bits and to erase, kill end-of-line and upper-case characters when it reads a login name. - The baud rate can be established by BREAK character processing and by parsing the CONNECT status messages from Hayes(tm)-compatible modems. Other features: RTS/CTS flow control (SunOS4), alternate login program, does not use /etc/gettytab or /etc/gettydefs. The program works without modification under System V release 2 and SunOS 4.1/4.1.1. It probably also works with later System V releases. Wietse Venema (wietse@wzv.win.tue.nl) #! /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_README' X@(#) README 1.8 9/1/91 23:32:37 X XThis is a SYSV/SunOS4 getty program with useful features for hardwired Xand dial-in tty lines. X X- The program adapts the tty modes to parity bits and to erase, kill Xend-of-line and upper-case characters when it reads a login name. X X- The baud rate can be established by BREAK character processing and by Xparsing the CONNECT status messages from Hayes-compatible modems. X XOther features: RTS/CTS flow control (SunOS4, suggested by John Harkin, X), alternate login program, does not use /etc/gettytab Xor /etc/gettydefs. X XThe program works without modification under System V release 2 and XSunOS 4.1/4.1.1. It probably also works with later System V releases. X XIn the Makefile you will have to specify whether diagnostics should be Xreported through the syslog daemon; the alternative is that all error Xreports go directly to /dev/console. X XThe command-line interface was cleaned up a bit; it is slightly Xincompatible with earlier agetty versions. X X Wietse Venema (wietse@wzv.win.tue.nl) END_OF_README if test 1033 -ne `wc -c agetty.c <<'END_OF_agetty.c' X/*++ X/* NAME X/* agetty 8 X/* SUMMARY X/* alternative System V/SunOS 4 getty X/* SYSTEM V SYNOPSIS X/* agetty [-i] [-l login_program] [-m] [-t timeout] port baud_rate,... X/* SUNOS 4 SYNOPSIS X/* agetty [-h] [-l login_program] [-m] [-t timeout] baud_rate,... port X/* DESCRIPTION X/* \fIagetty\fP opens a tty port, prompts for a login name and invokes X/* the /bin/login command. It is normally invoked by \fIinit(8)\fP. X/* X/* \fIagetty\fP has several \fInon-standard\fP features that are useful X/* for hard-wired and for dial-in lines: X/* .IP o X/* Adapts the tty settings to parity bits and to erase, kill, X/* end-of-line and uppercase characters when it reads a login name. X/* The program can handle 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 deduces the baud rate from the CONNECT messages produced by X/* Hayes(tm)-compatible modems. X/* .IP o X/* Optionally does not hang up when it is given an already opened line X/* (useful for call-back applications). X/* .IP o X/* Optionally does not display the contents of the \fI/etc/issue\fP file X/* (System V only). X/* .IP o X/* Optionally invokes a non-standard login program instead of X/* \fI/bin/login\fP. X/* .IP o X/* Optionally turns on hard-ware flow control (SunOS 4 only). X/* .PP X/* This program does not use the \fI/etc/gettydefs\fP (System V) or X/* \fI/etc/gettytab\fP (SunOS 4) files. X/* ARGUMENTS X/* .fi X/* .ad X/* .TP X/* port X/* A path name relative to the \fI/dev\fP directory. If a "-" is X/* specified, \fIagetty\fP assumes that its standard input is X/* already connected to a tty port and that a connection to a X/* remote user has already been established. X/* .sp X/* Under System V, a "-" \fIport\fP argument should be preceded X/* by a "--". X/* .TP X/* baud_rate,... X/* A comma-separated list of one or more baud rates. Each time X/* \fIagetty\fP receives a BREAK character it advances through X/* the list, which is treated as if it were circular. X/* .sp X/* Baud rates should be specified in descending order, so that the X/* null character (Ctrl-@) can also be used for baud rate switching. X/* OPTIONS X/* .fi X/* .ad X/* .TP X/* -h (SunOS 4 only) X/* Enable hardware (RTS/CTS) flow control. It is left up to the X/* application to disable software (XON/XOFF) flow protocol where X/* appropriate. X/* .TP X/* -i (System V only) X/* Do not display the contents of \fI/etc/issue\fP before writing the X/* login prompt. Terminals or communications hardware 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/* -l login_program X/* Invoke the specified \fIlogin_program\fP instead of /bin/login. X/* This allows the use of a non-standard login program (for example, X/* one that asks for a dial-up password or that uses a different X/* password file). X/* .TP X/* -m X/* Try to extract the baud rate the \fIconnect\fP status message X/* produced by some Hayes(tm)-compatible modems. These status X/* messages are of the form: "". X/* \fIagetty\fP assumes that the modem emits its status message at X/* the same speed as specified with (the first) \fIbaud_rate\fP value X/* on the command line. X/* .sp X/* Since the \fI-m\fP feature may fail on heavily-loaded systems, X/* you still should enable BREAK processing by enumerating all X/* expected baud rates on the command line. X/* .TP X/* -t timeout X/* Terminate if no user name could be read within \fItimeout\fP X/* seconds. This option should probably not be used with hard-wired X/* lines. X/* SYSTEM V EXAMPLES X/* This section shows sample entries for the \fI/etc/inittab\fP file. X/* X/* For a hard-wired line: X/* .ti +5 X/* t0:2:respawn:/etc/agetty ttyM0 9600 X/* X/* For a dial-in line with a 2400/1200/300 baud modem: X/* .ti +5 X/* t1:2:respawn:/etc/agetty -mt60 ttyM1 2400,1200,300 X/* SUNOS 4 EXAMPLES X/* .ad X/* .fi X/* This section show sample entries for the \fI/etc/ttytab\fP file. X/* Note that init(8) appends the port name to the command X/* specified in the inittab file. X/* X/* For a hard-wired line: X/* .ti +5 X/* ttya "/usr/etc/agetty 9600" vt100 on local X/* X/* For a dial-in line with a 2400/1200/300 baud modem: X/* .ti +5 X/* ttyb "/usr/etc/agetty -mt60 2400,1200,300" unknown on modem X/* X/* The latter also requires that the \fIDTR\fP and \fICD\fP modem X/* control lines are enabled (see the eeprom(8) manual page). X/* FILES X/* /etc/utmp, the system status file (System V only). X/* /etc/issue, printed before the login prompt (System V only). X/* /dev/console, problem reports (if syslog(3) is not used). X/* /etc/inittab (System V init(8) configuration file). X/* /etc/ttytab (SunOS 4 init(8) configuration file). X/* BUGS X/* The baud-rate detection feature (the \fI-m\fP option) requires that X/* \fIagetty\fP be 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\fP option in combination with a multiple baud X/* rate command-line argument, so that BREAK processing is enabled. X/* X/* The text in the /etc/issue file (System V only) and the login prompt X/* are always output with 7-bit characters and space parity. X/* X/* The baud-rate detection feature (the \fI-m\fP option) requires that X/* the modem emits its status message \fIafter\fP raising the DCD line. X/* DIAGNOSTICS X/* Depending on how the program was configured, all diagnostics are X/* written to the console device or reported via the syslog(3) facility. X/* Error messages are produced if the \fIport\fP argument does not X/* specify a terminal device; if there is no /etc/utmp entry for the X/* current process (System V only); 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/* 91/09/01 23:22:00 X/* VERSION/RELEASE X/* 1.29 X/*--*/ X X#ifndef lint Xchar sccsid[] = "@(#) agetty.c 1.29 9/1/91 23:22:00"; X#endif X X#include X#include X#include X#include X#include X#include X#include X#include X#include X X /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */ X X#ifdef USE_SYSLOG X#include Xextern void closelog(); X#endif X Xextern void exit(); X X /* X * Some heuristics to find out what environment we are in: if it is not X * System V, assume it is SunOS 4. X */ X X#ifdef LOGIN_PROCESS /* defined in System V utmp.h */ X#define SYSV_STYLE /* select System V style getty */ X#endif X X /* X * Things you may want to modify. 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. Relevant for System V only. 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#ifdef SYSV_STYLE X#define ISSUE "/etc/issue" /* displayed before the login prompt */ X#endif X X#define LOGIN "login: " /* login prompt */ 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_ERASE DEL /* default erase character */ 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_EOL 0 X#define DEF_SWITCH 0 /* default switch char */ X X /* X * SunOS 4.1.1 termio is broken. We must use the termios stuff instead, X * because the termio -> termios translation does not clear the termios X * CIBAUD bits. Therefore, the tty driver would sometimes report that input X * baud rate != output baud rate. I did not notice that problem with SunOS X * 4.1. We will use termios where available, and termio otherwise. X */ X X#ifdef TCGETS X#undef TCGETA X#undef TCSETA X#undef TCSETAW X#define termio termios X#define TCGETA TCGETS X#define TCSETA TCSETS X#define TCSETAW TCSETSW X#endif X X /* X * This program tries to not use the standard-i/o library. This keeps the X * executable small on systems that do not have shared libraries (System V X * Release <3). X */ X X#define BUFSIZ 1024 X X /* X * When multiple baud rates are specified on the command line, the first one X * we will try is the first one specified. X */ X X#define FIRST_SPEED 0 X X/* Storage for command-line options. */ X X#define MAX_SPEED 10 /* max. nr. of baud rates */ X Xstruct options { X int flags; /* toggle switches, see below */ X int timeout; /* time-out period */ X char *login; /* login program */ X int numspeed; /* number of baud rates to try */ X int speeds[MAX_SPEED]; /* 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_ISSUE (1<<1) /* display /etc/issue */ X#define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */ 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/* Initial values for the above. */ X Xstruct chardata init_chardata = { X DEF_ERASE, /* default erase character */ X DEF_KILL, /* default kill character */ X 0, /* always filled in at runtime */ X 0, /* space parity */ X 0, /* always filled in at runtime */ X}; X X/* The following is used for understandable diagnostics. */ X Xchar *progname; 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_ISSUE, /* show /etc/issue (SYSV_STYLE) */ X 0, /* no timeout */ X "/bin/login", /* default login program */ X 0, /* no baud rates known yet */ X }; X X /* The BSD-style init command passes us a useless process name. */ X X#ifdef SYSV_STYLE X progname = argv[0]; X#else X progname = "agetty"; X#endif X X /* Parse command-line arguments. */ X X parse_args(argc, argv, &options); X X /* Update the utmp file. */ X X#ifdef SYSV_STYLE X update_utmp(options.tty); X#endif X X /* Open the tty as standard { input, output, error }. */ X X open_tty(options.tty, &termio); X X /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */ X X termio_init(&termio, options.speeds[FIRST_SPEED]); 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 /* Set the optional timer. */ 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 timer. */ X X if (options.timeout) X (void) alarm(0); X X /* Finalize the termio settings. */ X X termio_final(&options, &termio, &chardata); X X /* Now the newline character should be properly written. */ X X (void) write(1, "\n", 1); X X /* Let the login program take care of password validation. */ X X (void) execl(options.login, options.login, logname, (char *) 0); X error("%s: can't exec %s: %m", options.tty, options.login); 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, "hil:mt:"))) { X switch (c) { X case 'h': /* enable h/w flow control */ X op->flags |= F_RTSCTS; X break; X case 'i': /* do not show /etc/issue */ X op->flags &= ~F_ISSUE; X break; X case 'l': X op->login = optarg; /* non-default login program */ 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 default: X usage(); X } X } X if (argc != optind + 2) /* check parameter count */ X usage(); X#ifdef SYSV_STYLE X op->tty = argv[optind++]; /* tty name */ X parse_speeds(op, argv[optind]); /* baud rate(s) */ X#else X parse_speeds(op, argv[optind++]); /* baud rate(s) */ X op->tty = argv[optind]; /* tty name */ X#endif 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 > MAX_SPEED) X error("too many alternate speeds"); X } X} X X#ifdef SYSV_STYLE 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: %m", 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("%s: no utmp entry", line); X } X} X X#endif X X/* open_tty - set up tty as standard { input, output, error } */ X Xopen_tty(tty, tp) Xchar *tty; Xstruct termio *tp; X{ X /* Get rid of the present standard { output, error} if any. */ X X (void) close(1); X (void) close(2); X errno = 0; /* ignore above errors */ X X /* Set up new standard input, unless we are given an already opened port. */ X X if (strcmp(tty, "-")) { X struct stat st; X X /* Sanity checks... */ X X if (chdir("/dev")) X error("/dev: chdir() failed: %m"); X if (stat(tty, &st) < 0) X error("/dev/%s: %m", tty); X if ((st.st_mode & S_IFMT) != S_IFCHR) X error("/dev/%s: not a character device", tty); X X /* Open the tty as standard input. */ X X (void) close(0); X errno = 0; /* ignore close(2) errors */ X X if (open(tty, 2) != 0) X error("/dev/%s: cannot open as standard input: %m", tty); X X } else { X X /* X * Standard input should already be connected to an open port. Make X * sure it is open for read/write. X */ X X if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) X error("%s: not open for read/write", tty); X } X X /* Set up standard output and standard error file descriptors. */ X X if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */ X error("%s: dup problem: %m", tty); /* we have a problem */ X X /* X * The following ioctl will fail if stdin is not a tty, but also when X * there is noise on the modem control lines. In the latter case, the X * common course of action is (1) fix your cables (2) give the modem more X * time to properly reset after hanging up. SunOS users can achieve (2) X * by patching the SunOS kernel variable "zsadtrlow" to a larger value; X * 5 seconds seems to be a good value. X */ X X if (ioctl(0, TCGETA, tp) < 0) X error("%s: ioctl: %m", tty); X X /* X * It seems to be a terminal. Set proper protections and ownership. Mode X * 0622 is suitable for SYSV <4 because /bin/login does not change X * protections. SunOS 4 login will change the protections to 0620 (write X * access for group tty) after the login has succeeded. X */ 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/* 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. Errors will be dealt with X * lateron. 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 unsigned 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 BREAK X * processing (comma-separated list of baud rates) if the processing of X * modem status messages is enabled. X */ X X /* X * Use 7-bit characters, don't block if input queue is empty. Errors will X * be dealt with lateron. X */ 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 terminal settings. Errors will be dealt with lateron. */ 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 (void) 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 is 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 static int baud_index = FIRST_SPEED;/* current speed index */ X X baud_index = (baud_index + 1) % op->numspeed; X tp->c_cflag &= ~CBAUD; X tp->c_cflag |= op->speeds[baud_index]; 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 etc. (also after switching speeds). */ X X *cp = init_chardata; X X /* Flush pending input (esp. after parsing or switching the baud rate). */ X X (void) sleep(1); X (void) ioctl(0, TCFLSH, (struct termio *) 0); X X /* Prompt for and 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 X /* Do not report trivial EINTR/EIO errors. */ X X if (read(0, &c, 1) < 1) { X if (errno == EINTR || errno == EIO) X exit(0); X error("%s: read: %m", 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 /* Handle names with upper case and no lower case. */ X X if (cp->capslock = caps_lock(logname)) { X for (bp = logname; *bp; bp++) X if (isupper(*bp)) X *bp = tolower(*bp); /* map name to lower case */ X } X return (logname); X} X X/* termio_final - set the final tty mode bits */ X Xtermio_final(op, tp, cp) Xstruct options *op; 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[VINTR] = DEF_INTR; /* default interrupt */ X tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ X tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ X tp->c_cc[VEOL] = DEF_EOL; X tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */ 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 /* Optionally enable hardware flow control */ X X#ifdef CRTSCTS X if (op->flags & F_RTSCTS) X tp->c_cflag |= CRTSCTS; X#endif X X /* Finally, make the new settings effective */ X X if (ioctl(0, TCSETA, tp) < 0) X error("%s: ioctl: TCSETA: %m", op->tty); X} X X/* caps_lock - string contains upper case without lower case */ X Xcaps_lock(s) Xchar *s; X{ X int capslock; X X for (capslock = 0; *s; s++) { X if (islower(*s)) X return (0); X if (capslock == 0) X capslock = isupper(*s); X } X return (capslock); X} X X/* bcode - convert speed string to speed code; return 0 on failure */ X Xbcode(s) Xchar *s; X{ X struct Speedtab { X long 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#ifdef B19200 X 19200, B19200, X#endif X#ifdef B38400 X 38400, B38400, X#endif X#ifdef EXTA X 19200, EXTA, X#endif X#ifdef EXTB X 38400, EXTB, X#endif X 0, 0, X }; X struct Speedtab *sp; X long atol(); X long speed = atol(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#ifdef SYSV_STYLE X static char msg[] = X "[-i] [-l login_program] [-m] [-t timeout] line baud_rate,..."; X#else X static char msg[] = X "[-h] [-l login_program] [-m] [-t timeout] baud_rate,... line"; X#endif X X error("usage: %s %s", progname, msg); X} X X/* error - report errors to console or syslog; only understands %s and %m */ 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#ifndef USE_SYSLOG X int fd; X#endif X char buf[BUFSIZ]; X char *bp; X extern char *sys_errlist[]; X char *strcpy(); X char *strcat(); X X /* X * If the diagnostic is reported via syslog(3), the process name is X * automatically prepended to the message. If we write directly to X * /dev/console, we must prepend the process name ourselves. X */ X X#ifdef USE_SYSLOG X buf[0] = '\0'; X bp = buf; X#else X (void) str2cpy(buf, progname, ": "); X bp = buf + strlen(buf); X#endif X X /* X * %s expansion is done by hand. On a System V Release 2 system without X * shared libraries and without syslog(3), linking with the the stdio X * library would make the program three times as big... X * X * %m expansion is done here as well. Too bad syslog(3) does not have a X * vsprintf() like interface. X */ X X va_start(ap); X fmt = va_arg(ap, char *); X while (*fmt) { X if (strncmp(fmt, "%s", 2) == 0) { X (void) strcpy(bp, va_arg(ap, char *)); X bp += strlen(bp); X fmt += 2; X } else if (strncmp(fmt, "%m", 2) == 0) { X (void) strcpy(bp, sys_errlist[errno]); X bp += strlen(bp); X fmt += 2; X } else { X *bp++ = *fmt++; X } X } X *bp = 0; X va_end(ap); X X /* X * Write the diagnostic directly to /dev/console if we do not use the X * syslog(3) facility. X */ X X#ifdef USE_SYSLOG X (void) openlog(progname, LOG_PID, LOG_AUTH); X (void) syslog(LOG_ERR, "%s", buf); X closelog(); X#else X /* Terminate with CR-LF since the console mode is unknown. */ X (void) strcat(bp, "\r\n"); X if ((fd = open("/dev/console", 1)) >= 0) { X (void) write(fd, buf, strlen(buf)); X (void) close(fd); X } X#endif X (void) sleep((unsigned) 10); /* be kind to init(8) */ X exit(1); X} END_OF_agetty.c if test 28539 -ne `wc -c agetty.8 <<'END_OF_agetty.8' X.TH AGETTY 8 X.ad X.fi X.SH NAME Xagetty X\- Xalternative System V/SunOS 4 getty X.SH SYSTEM V SYNOPSIS X.na X.nf Xagetty [-i] [-l login_program] [-m] [-t timeout] port baud_rate,... X.SH SUNOS 4 SYNOPSIS X.na X.nf Xagetty [-h] [-l login_program] [-m] [-t timeout] baud_rate,... port X.SH DESCRIPTION X.ad X.fi X\fIagetty\fP opens a tty port, prompts for a login name and invokes Xthe /bin/login command. It is normally invoked by \fIinit(8)\fP. X X\fIagetty\fP has several \fInon-standard\fP features that are useful Xfor hard-wired and for dial-in lines: X.IP o XAdapts the tty settings to parity bits and to erase, kill, Xend-of-line and uppercase characters when it reads a login name. XThe program can handle 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 deduces the baud rate from the CONNECT messages produced by XHayes(tm)-compatible modems. X.IP o XOptionally does not hang up when it is given an already opened line X(useful for call-back applications). X.IP o XOptionally does not display the contents of the \fI/etc/issue\fP file X(System V only). X.IP o XOptionally invokes a non-standard login program instead of X\fI/bin/login\fP. X.IP o XOptionally turns on hard-ware flow control (SunOS 4 only). X.PP XThis program does not use the \fI/etc/gettydefs\fP (System V) or X\fI/etc/gettytab\fP (SunOS 4) files. X.SH ARGUMENTS X.na X.nf X.fi X.ad X.TP Xport XA path name relative to the \fI/dev\fP directory. If a "-" is Xspecified, \fIagetty\fP assumes that its standard input is Xalready connected to a tty port and that a connection to a Xremote user has already been established. X.sp XUnder System V, a "-" \fIport\fP argument should be preceded Xby a "--". X.TP Xbaud_rate,... XA comma-separated list of one or more baud rates. Each time X\fIagetty\fP receives a BREAK character it advances through Xthe list, which is treated as if it were circular. X.sp XBaud rates should be specified in descending order, so that the Xnull character (Ctrl-@) can also be used for baud rate switching. X.SH OPTIONS X.na X.nf X.fi X.ad X.TP X-h (SunOS 4 only) XEnable hardware (RTS/CTS) flow control. It is left up to the Xapplication to disable software (XON/XOFF) flow protocol where Xappropriate. X.TP X-i (System V only) XDo not display the contents of \fI/etc/issue\fP before writing the Xlogin prompt. Terminals or communications hardware 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-l login_program XInvoke the specified \fIlogin_program\fP instead of /bin/login. XThis allows the use of a non-standard login program (for example, Xone that asks for a dial-up password or that uses a different Xpassword file). X.TP X-m XTry to extract the baud rate the \fIconnect\fP status message Xproduced by some Hayes(tm)-compatible modems. These status Xmessages are of the form: "". X\fIagetty\fP assumes that the modem emits its status message at Xthe same speed as specified with (the first) \fIbaud_rate\fP value Xon the command line. X.sp XSince the \fI-m\fP feature may fail on heavily-loaded systems, Xyou still should enable BREAK processing by enumerating all Xexpected baud rates on the command line. X.TP X-t timeout XTerminate if no user name could be read within \fItimeout\fP Xseconds. This option should probably not be used with hard-wired Xlines. X.SH SYSTEM V EXAMPLES X.na X.nf XThis section shows sample entries for the \fI/etc/inittab\fP file. X XFor a hard-wired line: X.ti +5 Xt0:2:respawn:/etc/agetty ttyM0 9600 X XFor a dial-in line with a 2400/1200/300 baud modem: X.ti +5 Xt1:2:respawn:/etc/agetty -mt60 ttyM1 2400,1200,300 X.SH SUNOS 4 EXAMPLES X.na X.nf X.ad X.fi XThis section show sample entries for the \fI/etc/ttytab\fP file. XNote that init(8) appends the port name to the command Xspecified in the inittab file. X XFor a hard-wired line: X.ti +5 Xttya "/usr/etc/agetty 9600" vt100 on local X XFor a dial-in line with a 2400/1200/300 baud modem: X.ti +5 Xttyb "/usr/etc/agetty -mt60 2400,1200,300" unknown on modem X XThe latter also requires that the \fIDTR\fP and \fICD\fP modem Xcontrol lines are enabled (see the eeprom(8) manual page). X.SH FILES X.na X.nf X/etc/utmp, the system status file (System V only). X/etc/issue, printed before the login prompt (System V only). X/dev/console, problem reports (if syslog(3) is not used). X/etc/inittab (System V init(8) configuration file). X/etc/ttytab (SunOS 4 init(8) configuration file). X.SH BUGS X.ad X.fi XThe baud-rate detection feature (the \fI-m\fP option) requires that X\fIagetty\fP be 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\fP option in combination with a multiple baud Xrate command-line argument, so that BREAK processing is enabled. X XThe text in the /etc/issue file (System V only) and the login prompt Xare always output with 7-bit characters and space parity. X XThe baud-rate detection feature (the \fI-m\fP option) requires that Xthe modem emits its status message \fIafter\fP raising the DCD line. X.SH DIAGNOSTICS X.ad X.fi XDepending on how the program was configured, all diagnostics are Xwritten to the console device or reported via the syslog(3) facility. XError messages are produced if the \fIport\fP argument does not Xspecify a terminal device; if there is no /etc/utmp entry for the Xcurrent process (System V only); 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 X91/09/01 23:22:00 X.SH VERSION/RELEASE X.na X.nf X1.29 END_OF_agetty.8 if test 5874 -ne `wc -c Makefile <<'END_OF_Makefile' X# @(#) Makefile 1.5 9/1/91 23:21:21 X X# On the CFLAGS line, specify -DUSE_SYSLOG if you want diagnostics to be X# reported via the syslog(3) facility. Otherwise, agetty will report its X# problems to /dev/console. X XSHELL = /bin/sh XCFLAGS = -s -O # -DUSE_SYSLOG 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_Makefile if test 448 -ne `wc -c