home *** CD-ROM | disk | FTP | other *** search
- /*++
- /* NAME
- /* agetty 8
- /* SUMMARY
- /* alternative SunOS 4/System V getty
- /* SUNOS 4 SYNOPSIS
- /* agetty [-l login_program] [-m] [-t timeout] baud_rate,... port
- /* SYSTEM V SYNOPSIS
- /* agetty [-i] [-l login_program] [-m] [-t timeout] port baud_rate,...
- /* DESCRIPTION
- /* \fIagetty\fP opens a tty port, prompts for a login name and invokes the
- /* /bin/login command. It is normally invoked by \fIinit(8)\fP.
- /*
- /* \fIagetty\fP has several \fInon-standard\fP features that are useful
- /* for hard-wired or dial-in lines:
- /* .IP o
- /* Adapts the tty settings to parity bits and to the erase, kill and
- /* end-of-line characters found while reading from standard input. The
- /* program understands 7-bit characters with even, odd, none or space
- /* parity, and 8-bit characters with no parity. The following special
- /* characters are recognized: @ and Control-U (kill); #, DEL and
- /* back space (erase); carriage return and line feed (end of line).
- /* .IP o
- /* Optionally recognizes the baud rate of incoming calls from the
- /* status messages produced by some multi-speed Hayes-compatible modems.
- /* .IP o
- /* Optionally does not display the contents of the \fI/etc/issue\fP file.
- /* This is relevant only for System V.
- /* .IP o
- /* Optionally invokes a non-standard login program instead of
- /* \fI/bin/login\fP.
- /* .PP
- /* This program does not use the \fI/etc/gettydefs\fP (System V) or
- /* \fI/etc/gettytab\fP (SunOS 4) files.
- /* ARGUMENTS
- /* .fi
- /* .ad
- /* .TP
- /* port
- /* A path name relative to the \fI/dev\fP directory.
- /* .TP
- /* baud_rate,...
- /* A comma-separated list of one or more baud rates. If more than one
- /* baud rate is specified, the BREAK character can be used to select
- /* the next baud rate in the list (or the first baud rate if the end
- /* of the list was reached).
- /* It is preferable to specify baud rates in descending order, so that
- /* the null character can also be used for baud-rate switching.
- /* OPTIONS
- /* .fi
- /* .ad
- /* .TP
- /* -i (System V only)
- /* Do not display the contents of \fI/etc/issue\fP before writing the
- /* login prompt. Terminals or communications hardware may become confused
- /* when receiving lots of text at the wrong baud rate; dial-up scripts
- /* may fail if the login prompt is preceded by too much text.
- /* .TP
- /* -l login_program
- /* Invoke the specified \fIlogin_program\fP instead of /bin/login.
- /* This allows the use of a non-standard login program (for example,
- /* one that asks for a dial-up password).
- /* .TP
- /* -m
- /* Try to extract the baud rate of incoming calls from the status message
- /* produced by some multi-speed Hayes-compatible modems. These usually
- /* produce a status message of the form: "<junk><speed><junk>".
- /* If no \fIspeed\fP is recognized within one second, \fIagetty\fP
- /* will use the (first) \fIbaud_rate\fP value specified on the command
- /* line. Since the \fI-m\fP feature will work only on lightly-loaded
- /* systems, you still should specify all possible baud rates on the
- /* command line in order to enable baud-rate selection with the
- /* BREAK character.
- /* .TP
- /* -t timeout
- /* Terminate the program if no user name could be read within
- /* \fItimeout\fP seconds. This option should probably not be used
- /* with hard-wired lines.
- /* SYSTEM V EXAMPLES
- /* For a hard-wired line:
- /* .ti +5
- /* t0:2:respawn:/etc/agetty ttyM0 9600
- /*
- /* For a dial-in line with a 300/1200/2400 baud multi-speed modem:
- /* .ti +5
- /* t1:2:respawn:/etc/agetty -t60 -m ttyM1 2400,1200,300
- /* SUNOS 4 EXAMPLES
- /* For a hard-wired line:
- /* .ti +5
- /* ttya "/usr/etc/agetty 9600" vt100 on local
- /*
- /* For a dial-in line with a 300/1200/2400 baud multi-speed modem:
- /* .ti +5
- /* ttyb "/usr/etc/agetty -mt60 2400,1200,300" unknown on modem
- /* FILES
- /* /etc/utmp, the system status file (System V only).
- /* /etc/issue, printed before the login prompt (System V only).
- /* /dev/console, problem reports (if syslog(3) is not used).
- /* /etc/inittab (System V init(8) configuration file).
- /* /etc/ttytab (SunOS 4 init(8) configuration file).
- /* BUGS
- /* The baud-rate detection code (the \fI-m\fP option) requires that
- /* \fIagetty\fP be scheduled soon enough after completion of a dial-in
- /* call (within 30 ms with modems that talk at 2400 baud). For robustness,
- /* always use the \fI-m\fP option in combination with a multiple baud
- /* rate command-line argument.
- /*
- /* The text in the /etc/issue file (System V only) and the login prompt
- /* are always output with space parity.
- /* DIAGNOSTICS
- /* Depending on how the program was configured, all diagnostics are
- /* written to the console device or reported via the syslog(3) facility.
- /* Error messages are produced if the \fIport\fP argument does not
- /* specify a terminal device; if there is no /etc/utmp entry for the
- /* current process (System V only); and so on.
- /* AUTHOR(S)
- /* W.Z. Venema <wietse@wzv.win.tue.nl>
- /* Eindhoven University of Technology
- /* Department of Mathematics and Computer Science
- /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- /* CREATION DATE
- /* Sat Nov 25 22:51:05 MET 1989
- /* LAST MODIFICATION
- /* 90/12/22 20:32:05
- /* VERSION/RELEASE
- /* 1.28
- /*--*/
-
- #ifndef lint
- static char sccsid[] = "@(#) agetty.c 1.28 12/22/90 20:32:05";
- #endif
-
- #include <termio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <varargs.h>
- #include <ctype.h>
- #include <utmp.h>
-
- /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
-
- #ifdef USE_SYSLOG
- #include <syslog.h>
- extern void closelog();
- #endif
-
- extern void exit();
-
- /*
- * Some heuristics to find out what environment we are in: if it is not
- * System V, assume it is SunOS 4.
- */
-
- #ifdef LOGIN_PROCESS /* defined in System V utmp.h */
- #define SYSV_STYLE /* Select System V style getty */
- #endif
-
- /*
- * Things you may want to modify.
- *
- * If ISSUE is not defined, agetty will never display the contents of the
- * /etc/issue file. You will not want to spit out large "issue" files at the
- * wrong baud rate. Relevant for System V only.
- *
- * You may disagree with the default line-editing etc. characters defined
- * below. Note, however, that DEL cannot be used for interrupt generation
- * and for line editing at the same time.
- */
-
- #ifdef SYSV_STYLE
- #define ISSUE "/etc/issue" /* displayed before the login prompt */
- #endif
-
- #define LOGIN "login: " /* login prompt */
-
- /* Some shorthands for control characters. */
-
- #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
- #define CR CTL('M') /* carriage return */
- #define NL CTL('J') /* line feed */
- #define BS CTL('H') /* back space */
- #define DEL CTL('?') /* delete */
-
- /* Defaults for line-editing etc. characters; you may want to change this. */
-
- #ifdef SYSV_STYLE
- #define DEF_ERASE BS /* default erase character */
- #else
- #define DEF_ERASE DEL /* default erase character */
- #endif
- #define DEF_INTR CTL('C') /* default interrupt character */
- #define DEF_QUIT CTL('\\') /* default quit char */
- #define DEF_KILL CTL('U') /* default kill char */
- #define DEF_EOF CTL('D') /* default EOF char */
- #define DEF_EOL 0
- #define DEF_SWITCH 0 /* default switch char */
-
- /*
- * This program tries to not use the standard-i/o library. This keeps the
- * executable small on systems that do not have shared libraries (System V
- * Release <3).
- */
-
- #define BUFSIZ 1024
-
- /* Storage for command-line options. */
-
- #define MAXSPEED 10
-
- struct options {
- int flags; /* toggle switches, see below */
- int timeout; /* time-out period */
- char *login; /* login program */
- int numspeed; /* number of baud rates to try */
- int curspeed; /* current speed */
- int speeds[MAXSPEED]; /* baud rates to be tried */
- char *tty; /* name of tty */
- };
-
- #define F_PARSE (1<<0) /* process modem status messages */
- #define F_ISSUE (1<<1) /* display /etc/issue */
-
- /* Storage for things detected while the login name was read. */
-
- struct chardata {
- int erase; /* erase character */
- int kill; /* kill character */
- int eol; /* end-of-line character */
- int parity; /* what parity did we see */
- int capslock; /* upper case without lower case */
- };
-
- /* The following is used for understandable diagnostics. */
-
- extern int errno;
- static char *procname;
-
- /* ... */
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- char *logname; /* login name, given to /bin/login */
- char *get_logname();
- struct chardata chardata; /* set by get_logname() */
- struct termio termio; /* terminal mode bits */
- static struct options options = {
- F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
- 0, /* no timeout */
- "/bin/login", /* default login program */
- 0, /* no baud rates known yet */
- };
-
- /* The BSD-style init command passes us a useless process name. */
-
- #ifdef SYSV_STYLE
- procname = argv[0];
- #else
- procname = "agetty";
- #endif
-
- /* Parse command-line arguments. */
-
- parse_args(argc, argv, &options);
-
- /* Update the utmp file. */
-
- #ifdef SYSV_STYLE
- update_utmp(options.tty);
- #endif
-
- /* Open the tty as standard { input, output, error }. */
-
- open_tty(options.tty, &termio);
-
- /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
-
- termio_init(&termio, options.speeds[0]);
-
- /* Optionally detect the baud rate from the modem status message. */
-
- if (options.flags & F_PARSE)
- auto_baud(&termio);
-
- /* With dial-in lines, briefly pause to allow modems etc. to settle. */
-
- if (options.timeout)
- (void) sleep(1);
-
- /* Optional time-out feature. */
-
- if (options.timeout)
- (void) alarm((unsigned) options.timeout);
-
- /* Read the login name. */
-
- while ((logname = get_logname(&options, &chardata, &termio)) == 0)
- next_speed(&termio, &options);
-
- /* Disable time-out feature. */
-
- if (options.timeout)
- (void) alarm(0);
-
- /* Finalize the termio settings. */
-
- termio_final(&termio, &chardata);
-
- /* Now the newline character should be properly written. */
-
- (void) write(1, "\n", 1);
-
- /* Let the login program take care of password validation. */
-
- (void) execl(options.login, options.login, logname, (char *) 0);
- error("%s: can't exec %s: %m", options.tty, options.login);
- /* NOTREACHED */
- }
-
- /* parse-args - parse command-line arguments */
-
- parse_args(argc, argv, op)
- int argc;
- char **argv;
- struct options *op;
- {
- extern char *optarg; /* getopt */
- extern int optind; /* getopt */
- int c;
-
- while (isascii(c = getopt(argc, argv, "a:il:mt:"))) {
- switch (c) {
- case 'i': /* do not show /etc/issue */
- op->flags &= ~F_ISSUE;
- break;
- case 'l':
- op->login = optarg; /* non-default login program */
- break;
- case 'm': /* parse modem status message */
- op->flags |= F_PARSE;
- break;
- case 't': /* time out */
- if ((op->timeout = atoi(optarg)) <= 0)
- error("bad timeout value: %s", optarg);
- break;
- case '?':
- usage();
- }
- }
- if (argc != optind + 2) /* check parameter count */
- usage();
- #ifdef SYSV_STYLE
- op->tty = argv[optind++]; /* tty name */
- parse_speeds(op, argv[optind]); /* baud rate(s) */
- #else
- parse_speeds(op, argv[optind]); /* baud rate(s) */
- op->tty = argv[++optind]; /* tty name */
- #endif
- }
-
- /* parse_speeds - parse alternate baud rates */
-
- parse_speeds(op, arg)
- struct options *op;
- char *arg;
- {
- char *strtok();
- char *cp;
-
- for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
- if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
- error("bad speed: %s", cp);
- if (op->numspeed > MAXSPEED)
- error("too many alternate speeds");
- }
- }
-
- #ifdef SYSV_STYLE
-
- /* update_utmp - update our utmp entry */
-
- update_utmp(line)
- char *line;
- {
- struct utmp ut;
- long ut_size = sizeof(ut); /* avoid nonsense */
- int ut_fd;
- int mypid = getpid();
- long time();
- long lseek();
- char *strncpy();
-
- /*
- * The utmp file holds miscellaneous information about things started by
- * /etc/init and other system-related events. Our purpose is to update
- * the utmp entry for the current process, in particular the process type
- * and the tty line we are listening to. Return successfully only if the
- * utmp file can be opened for update, and if we are able to find our
- * entry in the utmp file.
- */
-
- if ((ut_fd = open(UTMP_FILE, 2)) < 0) {
- error("%s: open for update: %m", UTMP_FILE);
- } else {
- while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) {
- if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) {
- ut.ut_type = LOGIN_PROCESS;
- ut.ut_time = time((long *) 0);
- (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name));
- (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
- (void) lseek(ut_fd, -ut_size, 1);
- (void) write(ut_fd, (char *) &ut, sizeof(ut));
- (void) close(ut_fd);
- return;
- }
- }
- error("no utmp entry found for process id %u", mypid);
- }
- }
-
- #endif
-
- /* open_tty - open tty as standard { input, output, error } */
-
- open_tty(tty, tp)
- char *tty;
- struct termio *tp;
- {
- struct stat st;
-
- /* Close standard { input, output, error } files, just in case. */
-
- (void) close(0);
- (void) close(1);
- (void) close(2);
- errno = 0; /* ignore above errors */
-
- /* Make sure we are given a character device. */
-
- if (chdir("/dev"))
- error("/dev: chdir() failed: %m");
- if (stat(tty, &st) < 0)
- error("/dev/%s: %m", tty);
- if ((st.st_mode & S_IFMT) != S_IFCHR)
- error("/dev/%s: not a character device", tty);
-
- /* Set up new standard input, output and error files. */
-
- if (open(tty, 2) != 0) /* set up std input */
- error("/dev/%s: cannot open as standard input: %m", tty);
- if (dup(0) != 1 || dup(0) != 2) /* set up std out and std err */
- error("%s: dup problem: %m", tty); /* we have a problem */
- if (ioctl(0, TCGETA, tp) < 0) /* read tty status bits */
- error("%s: ioctl failed: %m", tty); /* this is not a terminal */
-
- /* It seems to be a terminal; set proper protections and ownership. */
-
- (void) chown(tty, 0, 0); /* root, sys */
- (void) chmod(tty, 0622); /* crw--w--w- */
- errno = 0; /* ignore above errors */
- }
-
- /* termio_init - initialize termio settings */
-
- termio_init(tp, speed)
- struct termio *tp;
- int speed;
- {
-
- /*
- * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
- * Special characters are set after we have read the login name; all
- * reads will be done in raw mode anyway.
- */
-
- tp->c_cflag = CS8 | HUPCL | CREAD | speed;
- tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0;
- tp->c_cc[VMIN] = 1;
- tp->c_cc[VTIME] = 0;
- (void) ioctl(0, TCSETA, tp);
- }
-
- /* auto_baud - extract baud rate from modem status message */
-
- auto_baud(tp)
- struct termio *tp;
- {
- int speed;
- int vmin;
- int iflag;
- char buf[BUFSIZ];
- char *bp;
- int nread;
-
- /*
- * This works only if the modem produces its status code AFTER raising
- * the DCD line, and if the computer is fast enough to set the proper
- * baud rate before the message has gone by. We expect a message of the
- * following format:
- *
- * <junk><number><junk>
- *
- * The number is interpreted as the baud rate of the incoming call. If the
- * modem does not tell us the baud rate within one second, we will keep
- * using the current baud rate. It is advisable to enable baud-rate
- * cycling (comma-separated list of baud rates) if the processing of modem
- * status messages is enabled.
- */
-
- /* Use 7-bit characters, don't block if input queue is empty. */
-
- iflag = tp->c_iflag;
- tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
- vmin = tp->c_cc[VMIN];
- tp->c_cc[VMIN] = 0; /* don't block if queue empty */
- (void) ioctl(0, TCSETA, tp);
-
- /*
- * Wait for a while, then read everything the modem has said so far and
- * try to extract the speed of the dial-in call.
- */
-
- (void) sleep(1);
- if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
- buf[nread] = '\0';
- for (bp = buf; bp < buf + nread; bp++) {
- if (isascii(*bp) && isdigit(*bp)) {
- if (speed = bcode(bp)) {
- tp->c_cflag &= ~CBAUD;
- tp->c_cflag |= speed;
- }
- break;
- }
- }
- }
- /* Restore terminal settings. */
-
- tp->c_iflag = iflag;
- tp->c_cc[VMIN] = vmin;
- (void) ioctl(0, TCSETA, tp);
- }
-
- /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
-
- do_prompt(op, tp)
- struct options *op;
- struct termio *tp;
- {
- #ifdef ISSUE
- int fd;
- int oflag;
- int n;
- char buf[BUFSIZ];
- #endif
-
- write(1, "\r\n", 2); /* start a new line */
- #ifdef ISSUE /* optional: show /etc/issue */
- if ((op->flags & F_ISSUE) && (fd = open(ISSUE, 0)) >= 0) {
- oflag = tp->c_oflag; /* save current setting */
- tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */
- (void) ioctl(0, TCSETAW, tp);
- while ((n = read(fd, buf, sizeof(buf))) > 0)
- (void) write(1, buf, n);
- tp->c_oflag = oflag; /* restore settings */
- (void) ioctl(0, TCSETAW, tp); /* wait till output gone */
- (void) close(fd);
- }
- #endif
- (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */
- }
-
- /* next_speed - select next baud rate */
-
- next_speed(tp, op)
- struct termio *tp;
- struct options *op;
- {
- op->curspeed = (op->curspeed + 1) % op->numspeed;
- tp->c_cflag &= ~CBAUD;
- tp->c_cflag |= op->speeds[op->curspeed];
- (void) ioctl(0, TCSETA, tp);
- }
-
- /* get_logname - get user name, establish parity, speed, erase, kill, eol */
-
- char *get_logname(op, cp, tp)
- struct options *op;
- struct chardata *cp;
- struct termio *tp;
- {
- char logname[BUFSIZ];
- char *bp;
- char c; /* input character, full eight bits */
- char ascval; /* low 7 bits of input character */
- int bits; /* # of "1" bits per character */
- int mask; /* mask with 1 bit up */
- static char *erase[] = { /* backspace-space-backspace */
- "\010\040\010", /* space parity */
- "\010\040\010", /* odd parity */
- "\210\240\210", /* even parity */
- "\210\240\210", /* no parity */
- };
-
- /* Initialize kill, erase, parity etc. (also after switching speeds). */
-
- cp->kill = DEF_KILL;
- cp->erase = DEF_ERASE;
- cp->parity = 0;
-
- /* Flush any pending input */
-
- (void) ioctl(0, TCFLSH, (struct termio *) 0);
-
- /* Read a login name. */
-
- for (*logname = 0; *logname == 0; /* void */ ) {
-
- /* Write issue file and prompt, with "parity" bit == 0. */
-
- do_prompt(op, tp);
-
- /* Read name, watch for break, parity, erase, kill, end-of-line. */
-
- for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
- if (read(0, &c, 1) < 1)
- error("%s: read: %m", op->tty);
-
- /* Do BREAK handling elsewhere. */
-
- if ((c == 0) && op->numspeed > 1)
- return (0);
-
- /* Do parity bit handling. */
-
- if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */
- for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
- if (mask & ascval)
- bits++; /* count "1" bits */
- cp->parity |= ((bits & 1) ? 1 : 2);
- }
- /* Do erase, kill and end-of-line processing. */
-
- switch (ascval) {
- case CR:
- case NL:
- *bp = 0; /* terminate logname */
- cp->eol = ascval; /* set end-of-line char */
- break;
- case BS:
- case DEL:
- case '#':
- cp->erase = ascval; /* set erase character */
- if (bp > logname) {
- (void) write(1, erase[cp->parity], 3);
- bp--;
- }
- break;
- case CTL('U'):
- case '@':
- cp->kill = ascval; /* set kill character */
- while (bp > logname) {
- (void) write(1, erase[cp->parity], 3);
- bp--;
- }
- break;
- case CTL('D'):
- exit(0);
- default:
- if (!isascii(ascval) || !isprint(ascval)) {
- /* ignore garbage characters */ ;
- } else if (bp - logname >= sizeof(logname) - 1) {
- error("%s: input overrun", op->tty);
- } else {
- (void) write(1, &c, 1); /* echo the character */
- *bp++ = ascval; /* and store it */
- }
- break;
- }
- }
- }
- if (cp->capslock = caps_lock(logname)) { /* upper case w/o lower case? */
- for (bp = logname; *bp; bp++)
- if (isupper(*bp))
- *bp = tolower(*bp); /* map name to lower case */
- }
- return (logname);
- }
-
- /* termio_final - set the final tty mode bits */
-
- termio_final(tp, cp)
- struct termio *tp;
- struct chardata *cp;
- {
- /* General terminal-independent stuff. */
-
- tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */
- tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK;
- tp->c_oflag |= OPOST;
- tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */
- tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */
- tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */
- tp->c_cc[VEOL] = DEF_EOL;
- tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */
-
- /* Account for special characters seen in input. */
-
- if (cp->eol == CR) {
- tp->c_iflag |= ICRNL; /* map CR in input to NL */
- tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */
- }
- tp->c_cc[VERASE] = cp->erase; /* set erase character */
- tp->c_cc[VKILL] = cp->kill; /* set kill character */
-
- /* Account for the presence or absence of parity bits in input. */
-
- switch (cp->parity) {
- case 0: /* space (always 0) parity */
- break;
- case 1: /* odd parity */
- tp->c_cflag |= PARODD;
- /* FALLTHROUGH */
- case 2: /* even parity */
- tp->c_cflag |= PARENB;
- tp->c_iflag |= INPCK | ISTRIP;
- /* FALLTHROUGH */
- case (1 | 2): /* no parity bit */
- tp->c_cflag &= ~CSIZE;
- tp->c_cflag |= CS7;
- break;
- }
- /* Account for upper case without lower case. */
-
- if (cp->capslock) {
- tp->c_iflag |= IUCLC;
- tp->c_lflag |= XCASE;
- tp->c_oflag |= OLCUC;
- }
- /* Finally, make the new settings effective */
-
- (void) ioctl(0, TCSETA, tp);
- }
-
- /* caps_lock - string contains upper case without lower case */
-
- caps_lock(s)
- char *s;
- {
- int hascaps;
-
- for (hascaps = 0; *s; s++) {
- if (islower(*s))
- return (0);
- if (hascaps == 0)
- hascaps = isupper(*s);
- }
- return (hascaps);
- }
-
- /* bcode - convert speed string to speed code; return 0 on failure */
-
- bcode(s)
- char *s;
- {
- struct Speedtab {
- int speed;
- int code;
- };
- static struct Speedtab speedtab[] = {
- 50, B50,
- 75, B75,
- 110, B110,
- 134, B134,
- 150, B150,
- 200, B200,
- 300, B300,
- 600, B600,
- 1200, B1200,
- 1800, B1800,
- 2400, B2400,
- 4800, B4800,
- 9600, B9600,
- #ifdef B19200
- 19200, B19200,
- #endif
- #ifdef B38400
- 38400, B38400,
- #endif
- #ifdef EXTA
- 19200, EXTA,
- #endif
- 0, 0,
- };
- struct Speedtab *sp;
- int speed = atoi(s);
-
- for (sp = speedtab; sp->speed; sp++)
- if (sp->speed == speed)
- return (sp->code);
- return (0);
- }
-
- /* usage - explain */
-
- usage()
- {
- #ifdef SYSV_STYLE
- static char args[] =
- "[-i] [-l login_program] [-m] [-t timeout] line baud_rate,...";
- #else
- static char args[] =
- "[-l login_program] [-m] [-t timeout] baud_rate,... line";
- #endif
-
- error("usage: %s %s", procname, args);
- }
-
- /* error - report errors to the console; only understands %s and %m */
-
- #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
-
- /* VARARGS */
-
- error(va_alist)
- va_dcl
- {
- va_list ap;
- char *fmt;
- #ifndef USE_SYSLOG
- int fd;
- #endif
- char buf[BUFSIZ];
- char *bp;
- extern char *sys_errlist[];
- char *strcpy();
- char *strcat();
-
- /*
- * If the diagnostic is reported via syslog(3), the process name is
- * automatically prepended to the message. If we write directly to
- * /dev/console, we must prepend the process name ourselves.
- */
-
- #ifdef USE_SYSLOG
- buf[0] = '\0';
- bp = buf;
- #else
- (void) str2cpy(buf, procname, ": ");
- bp = buf + strlen(buf);
- #endif
-
- /*
- * %s expansion is done by hand. On a System V Release 2 system without
- * shared libraries and without syslog(3), linking with the the stdio
- * library would make the program three times as big...
- *
- * %m expansion is done here as well. Too bad syslog(3) does not have a
- * vsprintf() like interface.
- */
-
- va_start(ap);
- fmt = va_arg(ap, char *);
- while (*fmt) {
- if (strncmp(fmt, "%s", 2) == 0) {
- (void) strcpy(bp, va_arg(ap, char *));
- bp += strlen(bp);
- fmt += 2;
- } else if (strncmp(fmt, "%m", 2) == 0) {
- (void) strcpy(bp, sys_errlist[errno]);
- bp += strlen(bp);
- fmt += 2;
- } else {
- *bp++ = *fmt++;
- }
- }
- *bp = 0;
- va_end(ap);
-
- /*
- * Write the diagnostic directly to /dev/console if we do not use the
- * syslog(3) facility.
- */
-
- #ifdef USE_SYSLOG
- (void) openlog(procname, LOG_PID, LOG_AUTH);
- (void) syslog(LOG_ERR, "%s", buf);
- closelog();
- #else
- /* Terminate with CR-LF since the console mode is unknown. */
- (void) strcat(bp, "\r\n");
- if ((fd = open("/dev/console", 1)) >= 0) {
- (void) write(fd, buf, strlen(buf));
- (void) close(fd);
- }
- #endif
- (void) sleep(5); /* be kind to init */
- exit(1);
- }
-