home *** CD-ROM | disk | FTP | other *** search
- /*
- * dip A program for handling dialup IP connecions.
- * UNIX terminal I/O support functions. This file takes
- * care of opening, setting up and maintaining the line,
- * and it takes care of allocating the buffers and init-
- * ializing their control structures.
- *
- * Version: @(#)tty.c 3.3.6 12/13/93
- * Modified: @(#)tty.c 3.3.7 05/22/94
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Copyright 1988-1993 MicroWalt Corporation
- * Lock file stuff stolen from Taylor UUCP
- * Copyright (C) 1991, 1992 Ian Lance Taylor
- *
- * Uri Blumenthal <uri@watson.ibm.com>
- * (C) 1994
- *
- * This program is free software; you can redistribute it
- * and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
- #include "dip.h"
- #include <sys/stat.h>
- #ifdef LINUX
- # include <linux/fs.h>
- # include <linux/tty.h>
- # include <linux/serial.h> /* for Linux-1.1.13 */
- #endif
-
-
- #define TTY_BUFSIZE 1024 /* size of one serial buffer */
-
-
- static struct {
- char *speed;
- int code;
- } tty_speeds[] = { /* table of usable baud rates */
- { "0", B0 },
- { "50", B50 }, { "75", B75 },
- { "110", B110 }, { "300", B300 },
- { "600", B600 }, { "1200", B1200 },
- { "2400", B2400 }, { "4800", B4800 },
- { "9600", B9600 },
- #ifdef B14400
- { "14400", B14400 },
- #endif
- #ifdef B19200
- { "19200", B19200 },
- #endif
- #ifdef B38400
- { "38400", B38400 },
- #endif
- #ifdef B57600
- { "57600", B57600 },
- #endif
- #ifdef B115200
- { "115200", B115200 },
- #endif
- { NULL, 0 }
- };
-
-
- static struct termios tty_saved; /* saved TTY device state */
-
- static struct termios tty_current; /* current TTY device state */
-
- static char *in_buff, /* line input/output buffers */
- *out_buff,
- *in_ptr,
- *out_ptr;
-
- static int in_size, /* buffer sizes and counters */
- out_size,
- in_cnt,
- out_cnt,
- tty_sdisc, /* saved TTY line discipline */
- tty_ldisc, /* current TTY line discipline */
- tty_fd = -1; /* TTY file descriptor */
-
-
- /* Disable any messages to the input channel of this process. */
- int
- tty_nomesg(void)
- {
- return(fchmod(0, 0600));
- }
-
-
- /* Lock or unlock a terminal line. */
- int
- tty_lock(char *path, int mode)
- {
- static char saved_path[PATH_MAX];
- static int saved_lock = 0;
- struct passwd *pw;
- #if !defined(linux)
- #if HAVE_V2_LOCKFILES
- int i;
- #else
- char ab[12];
- #endif
- int fd;
- pid_t ime;
- int cwrote;
- #endif
-
-
- if (mode == 1) { /* lock */
- if (path == NULL) return(0); /* standard input */
- sprintf(saved_path, "%s/LCK..%s", _PATH_LOCKD, path);
- #if 0
- if ((fd = creat(saved_path, 0644)) < 0) {
- if (errno != EEXIST)
- fprintf(stderr, "DIP: tty: lock: (%s): %s\n",
- saved_path, strerror(errno));
- return(-1);
- }
- ime = getpid ();
- #if HAVE_V2_LOCKFILES
- i = ime;
- cwrote = write (fd, &i, sizeof i);
- #else
- sprintf (ab, "%10d\n", (int) ime);
- cwrote = write (fd, ab, strlen (ab));
- #endif
- (void) close(fd);
- #else
- {
- FILE *fd;
- if ((fd = fopen(saved_path, "w")) == (FILE *)0) {
- syslog(LOG_ERR, "DIP: tty: lock: (%s): %s\n",
- saved_path, strerror(errno));
- fprintf(stderr, "DIP: tty: lock: (%s): %s\n",
- saved_path, strerror(errno));
- return(-1);
- }
- fprintf(fd, "%10d\n", (int)getpid());
- (void)fclose(fd);
- }
- #endif
-
- /* Make sure UUCP owns the lockfile. Required by some packages. */
- if ((pw = getpwnam(_UID_UUCP)) == NULL) {
- fprintf(stderr, "DIP: tty: lock: UUCP user %s unknown!\n",
- _UID_UUCP);
- return(0); /* keep the lock anyway */
- }
- (void) chown(saved_path, pw->pw_uid, pw->pw_gid);
- saved_lock = 1;
- } else {
- if (mode == 2) { /* re-acquire a lock after a fork() */
- FILE *fd;
-
- if (saved_lock != 1) {
- syslog(LOG_ERR,
- "DIP: tty_lock reaquire: lock was not saved!\n");
- return (-1);
- }
- if ((fd = fopen(saved_path, "w")) == (FILE *)0) {
- syslog(LOG_ERR, "DIP:tty_lock(%s) reaquire: %s\n",
- saved_path, strerror(errno));
- fprintf(stderr, "DIP:fork: tty: lock: (%s): %s\n",
- saved_path, strerror(errno));
- return(-1);
- }
- fprintf(fd, "%10d\n", (int)getpid());
- (void)fclose(fd);
- return(0);
- } else { /* unlock */
- FILE *fd;
-
- if (saved_lock != 1) {
- syslog(LOG_ERR, "DIP:tty_lock: lock was not saved?!\n");
- return(0);
- }
- if ((fd = fopen(saved_path, "w")) == (FILE *)0) {
- syslog(LOG_ERR, "DIP:tty_lock: can't reopen to delete: %s\n",
- strerror(errno));
- return (-1);
- }
- if (unlink(saved_path) < 0) {
- syslog(LOG_ERR, "DIP: tty: unlock: (%s): %s\n", saved_path,
- strerror(errno));
- fprintf(stderr, "DIP: tty: unlock: (%s): %s\n", saved_path,
- strerror(errno));
- saved_lock = 0;
- return(-1);
- }
- saved_lock = 0;
- }
- }
-
- return(0);
- }
-
-
- /* Find a serial speed code in the table. */
- static int
- tty_find_speed(char *speed)
- {
- int i;
-
- i = 0;
- while (tty_speeds[i].speed != NULL) {
- if (! strcmp(tty_speeds[i].speed, speed)) return(tty_speeds[i].code);
- i++;
- }
- return(-EINVAL);
- }
-
-
- /* Set the number of stop bits. */
- static int
- tty_set_stopbits(struct termios *tty, char *stopbits)
- {
- if (opt_v) printf("DIP: tty: set_stopbits: %c\n", *stopbits);
- switch(*stopbits) {
- case '1':
- tty->c_cflag &= ~CSTOPB;
- break;
-
- case '2':
- tty->c_cflag |= CSTOPB;
- break;
-
- default:
- return(-EINVAL);
- }
- return(0);
- }
-
-
- /* Set the number of data bits. */
- static int
- tty_set_databits(struct termios *tty, char *databits)
- {
- if (opt_v) printf("DIP: tty: set_databits: %c\n", *databits);
- tty->c_cflag &= ~CSIZE;
- switch(*databits) {
- case '5':
- tty->c_cflag |= CS5;
- break;
-
- case '6':
- tty->c_cflag |= CS6;
- break;
-
- case '7':
- tty->c_cflag |= CS7;
- break;
-
- case '8':
- tty->c_cflag |= CS8;
- break;
-
- default:
- return(-EINVAL);
- }
- return(0);
- }
-
-
- /* Set the type of parity encoding. */
- static int
- tty_set_parity(struct termios *tty, char *parity)
- {
- if (opt_v) printf("DIP: tty: set_parity: %c\n", *parity);
- switch(toupper(*parity)) {
- case 'N':
- tty->c_cflag &= ~(PARENB | PARODD);
- break;
-
- case 'O':
- tty->c_cflag &= ~(PARENB | PARODD);
- tty->c_cflag |= (PARENB | PARODD);
- break;
-
- case 'E':
- tty->c_cflag &= ~(PARENB | PARODD);
- tty->c_cflag |= (PARENB);
- break;
-
- default:
- return(-EINVAL);
- }
- return(0);
- }
-
-
- /* Set the line speed of a terminal line. */
- static int
- tty_set_speed(struct termios *tty, char *speed)
- {
- int code;
-
- if (opt_v) printf("DIP: tty: set_speed: %s\n", speed);
- code = tty_find_speed(speed);
- if (code < 0) return(-1);
- tty->c_cflag &= ~CBAUD;
- tty->c_cflag |= code;
-
- return(0);
- }
-
-
- /* Put a terminal line in a transparent state. */
- static int
- tty_set_raw(struct termios *tty)
- {
- int i;
- int speed;
-
- for(i = 0; i < NCCS; i++)
- tty->c_cc[i] = '\0'; /* no spec chr */
- tty->c_cc[VMIN] = 1;
- tty->c_cc[VTIME] = 0;
- tty->c_iflag = (IGNBRK | IGNPAR); /* input flags */
- tty->c_oflag = (0); /* output flags */
- tty->c_lflag = (0); /* local flags */
- speed = (tty->c_cflag & CBAUD); /* save current speed */
- tty->c_cflag = (CRTSCTS|HUPCL|CREAD|CLOCAL); /* UART flags */
- tty->c_cflag |= speed; /* restore speed */
- return(0);
- }
-
-
- /* Fetch the state of a terminal. */
- static int
- tty_get_state(struct termios *tty)
- {
- if (ioctl(tty_fd, TCGETS, tty) < 0) {
- syslog(LOG_ERR, "DIP: tty: get_state: %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: get_state: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Set the state of a terminal. */
- static int
- tty_set_state(struct termios *tty)
- {
-
- if (ioctl(tty_fd, TCSETS, tty) < 0) {
- syslog(LOG_ERR, "DIP: tty: set_state: %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: set_state: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Get the line discipline of a terminal line. */
- int
- tty_get_disc(int *disc)
- {
- if (ioctl(tty_fd, TIOCGETD, disc) < 0) {
- syslog(LOG_ERR, "DIP: tty: get_disc: %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: get_disc: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Set the line discipline of a terminal line. */
- int
- tty_set_disc(int disc)
- {
-
- if (disc == -1) disc = tty_sdisc;
-
- if (ioctl(tty_fd, TIOCSETD, &disc) < 0) {
- syslog(LOG_ERR, "DIP: tty: set_disc(%d): %s\n", disc, strerror(errno));
- fprintf(stderr, "DIP: tty: set_disc(%d): %s\n", disc, strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Get the encapsulation type of a terminal line. */
- int
- tty_get_encap(int *encap)
- {
- if (ioctl(tty_fd, SIOCGIFENCAP, encap) < 0) {
- syslog(LOG_ERR, "DIP: tty: get_encap: %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: get_encap: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Set the encapsulation type of a terminal line. */
- int
- tty_set_encap(int encap)
- {
- if (ioctl(tty_fd, SIOCSIFENCAP, &encap) < 0) {
- fprintf(stderr, "DIP: tty: set_encap(%d): %s\n",
- encap, strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Fetch the name of the network interface attached to this terminal. */
- int
- tty_get_name(char *name)
- {
- if (ioctl(tty_fd, SIOCGIFNAME, name) < 0) {
- syslog(LOG_ERR, "DIP: tty_get_name: %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty_get_name: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Read one character (byte) from the TTY link. */
- int
- tty_getc(void)
- {
- int s;
-
- if (in_cnt <= 0) {
- s = read(tty_fd, in_buff, in_size);
- in_cnt = s;
- in_ptr = in_buff;
- }
-
- if (in_cnt < 0) {
- if (opt_v == 1) printf("DIP: tty: getc: I/O error.\n");
- return(-1);
- }
-
- s = (int) *in_ptr;
- s &= 0xFF;
- in_ptr++;
- in_cnt--;
- return(s);
- }
-
-
- /* Write one character (byte) to the TTY link. */
- int
- tty_putc(int c)
- {
- int s;
-
- if ((out_cnt == out_size) || (c == -1)) {
- s = write(tty_fd, out_buff, out_cnt);
- out_cnt = 0;
- out_ptr = out_buff;
- if (s < 0) return(-1);
- }
-
- if (c != -1) {
- *out_ptr = (char) c;
- out_ptr++;
- out_cnt++;
- }
-
- return(0);
- }
-
-
- /* Output a string of characters to the TTY link. */
- void
- tty_puts(char *s)
- {
- while(*s != '\0') tty_putc((int) *s++);
- tty_putc(-1); /* flush */
- }
-
-
- /* Return the TTY link's file descriptor. */
- int
- tty_askfd(void)
- {
- return(tty_fd);
- }
-
-
- /* Set the number of databits a terminal line. */
- int
- tty_databits(char *bits)
- {
- if (tty_set_databits(&tty_current, bits) < 0) return(-1);
- return(tty_set_state(&tty_current));
- }
-
-
- /* Set the number of stopbits of a terminal line. */
- int
- tty_stopbits(char *bits)
- {
- if (tty_set_stopbits(&tty_current, bits) < 0) return(-1);
- return(tty_set_state(&tty_current));
- }
-
-
- /* Set the type of parity of a terminal line. */
- int
- tty_parity(char *type)
- {
- if (tty_set_parity(&tty_current, type) < 0) return(-1);
- return(tty_set_state(&tty_current));
- }
-
-
- /* Set the line speed of a terminal line. */
- int
- tty_speed(char *speed)
- {
- #if defined(LINUX)
- struct serial_struct info;
- int spd;
-
- spd = atoi(speed);
- if (ioctl(tty_fd, TIOCGSERIAL, &info)) return(-1);
- info.flags = info.flags & ~ASYNC_SPD_MASK;
-
- if (spd == 115200) {
- if (tty_set_speed(&tty_current, "38400") < 0) return(-1);
- info.flags |= ASYNC_SPD_VHI;
- } else if (spd == 57600) {
- if (tty_set_speed(&tty_current, "38400") < 0) return(-1);
- info.flags |= ASYNC_SPD_HI;
- } else {
- if (tty_set_speed(&tty_current, speed) < 0) return(-1);
- }
- if (ioctl(tty_fd, TIOCSSERIAL, &info)) return(-1);
- #else
- if (tty_set_speed(&tty_current, speed) < 0) return(-1);
- #endif
-
- return(tty_set_state(&tty_current));
- }
-
-
- /* Hangup the line. */
- int
- hanguptty(void)
- {
- struct termios tty;
-
- tty = tty_current;
- (void) tty_set_speed(&tty, "0");
- if (tty_set_state(&tty) < 0) {
- syslog(LOG_ERR, "DIP: tty: hangup(DROP): %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: hangup(DROP): %s\n", strerror(errno));
- return(-errno);
- }
-
- (void) sleep(3);
-
- if (tty_set_state(&tty_current) < 0) {
- syslog(LOG_ERR, "DIP: tty: hangup(RAISE): %s\n", strerror(errno));
- fprintf(stderr, "DIP: tty: hangup(RAISE): %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
- /* Clear the CLOCAL bit. (detect carrier loss) */
- int
- tty_notlocal(void)
- {
- /* Release any control terminal we might have. */
- if (setsid() < 0) {
- syslog(LOG_ERR,
- "DIP: tty_notlocal cannot setsid: %s\n", strerror(errno));
- fprintf(stderr,
- "DIP: tty_notlocal cannot setsid: %s\n", strerror(errno));
- }
-
- if (opt_v) {
- char ch0[20];
- char ch1[20];
-
- strcpy(ch0, ttyname(0));
- strcpy(ch1, ttyname(tty_fd));
- syslog(LOG_ERR, "tty_notlocal: fd0: %s fd%1d %s\n", ch0, tty_fd, ch1);
- }
-
- #if 1 /* don't know why... What's wrong with it?! */
- if (ioctl(tty_fd, TIOCSCTTY, 1) < 0) {
- syslog(LOG_ERR,
- "DIP: tty_notlocal cannot TIOCSCTTY: %s\n", strerror(errno));
- fprintf(stderr,
- "DIP: tty_notlocal cannot TIOCSCTTY: %s\n", strerror(errno));
- }
- #endif
- tty_current.c_cflag &= ~CLOCAL;
- if (tty_set_state(&tty_current) < 0) {
- syslog(LOG_ERR,
- "DIP: tty_notlocal cannot clr CLOCAL: %s\n", strerror(errno));
- fprintf(stderr,
- "DIP: tty_notlocal cannot clr CLOCAL: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
- int tty_login(void)
- {
- if (ioctl(tty_fd, TIOCSCTTY, 1) < 0)
- syslog(LOG_ERR,
- "DIP: tty_login cannot TIOCSCTTY: %s\n", strerror(errno));
- tty_current.c_cflag &= ~CLOCAL;
- if (tty_set_state(&tty_current) < 0)
- syslog(LOG_ERR,
- "DIP: tty_notlocal cannot clr CLOCAL: %s\n", strerror(errno));
- return 0;
- } /* tty_login() */
-
-
- /* Flush input on the terminal. */
- int
- tty_flush(void)
- {
- int blkmode;
- char buf;
-
- blkmode = fcntl(tty_fd, F_GETFL, NULL);
- fcntl(tty_fd, F_SETFL, (O_NDELAY | blkmode));
- while (read(tty_fd, &buf, 1) > 0)
- ;
- fcntl(tty_fd, F_SETFL, blkmode);
- return(0);
- }
-
-
- /* Close down a terminal line. */
- int
- tty_close(void)
- {
- (void) tty_set_disc(tty_sdisc);
-
- if (tty_set_state(&tty_saved) < 0) {
- syslog(LOG_ERR, "DIP: tty:tcsetattr(tty_saved): %s\n",
- strerror(errno));
- fprintf(stderr, "DIP: tty: restore: %s\n", strerror(errno));
- (void) tty_lock("no_diff", 0);
- return(-errno);
- }
-
- (void) tty_lock("dont_care", 0);
- (void) hanguptty();
- (void) mdm_hangup();
-
- return(0);
- }
-
-
- int tty_login_close(void)
- {
- #if 0
- char ifname[32];
-
- (void) tty_get_name(ifname);
- (void) detach(ifname);
-
- (void) tty_set_disc(tty_sdisc);
-
- if (tcsetattr(tty_fd, TCSAFLUSH, &tty_saved) < 0)
- syslog(LOG_ERR, "DIP: tty_login_close:tcsetattr(tty_saved): %s\n",
- strerror(errno));
- #endif
- (void) mdm_hangup();
-
- return 0;
- }
-
-
- /* Open and initialize a terminal line. */
- int
- tty_open(char *name)
- {
- char path[PATH_MAX];
- register char *sp;
- int fd,flags;
-
- /* Try opening the TTY device. */
- if (name != NULL) {
- if ((sp = strrchr(name, '/')) != (char *)NULL) *sp++ = '\0';
- else sp = name;
- sprintf(path, "/dev/%s", sp);
- if ((fd = open(path, O_RDWR|O_NDELAY)) < 0) {
- fprintf(stderr, "DIP: tty: open(%s, RW): %s\n",
- path, strerror(errno));
- return(-errno);
- }
- tty_fd = fd;
- if (opt_v) {
- printf("DIP: tty: open: %s (%d) ", path, fd);
- syslog(LOG_INFO, "DIP: tty: open: %s (%d) ", path, fd);
- }
- } else {
- tty_fd = 0;
- sp = (char *)NULL;
- }
-
- if(tty_lock(sp, 1)) {
- fprintf(stderr, "DIP: problems with locking %s\n",
- sp);
- return (-1);
- }
-
- /* Size and allocate the I/O buffers. */
- in_size = TTY_BUFSIZE;
- out_size = in_size;
- in_buff = (char *) malloc(in_size);
- out_buff = (char *) malloc(out_size);
- if (in_buff == (char *)NULL || out_buff == (char *)NULL) {
- fprintf(stderr, "DIP: tty: open: cannot alloc(%d, %d) buffers (%d)\n",
- in_size, out_size, errno);
- return(-ENOMEM);
- }
- in_cnt = 0;
- out_cnt = 0;
- in_ptr = in_buff;
- out_ptr = out_buff;
- out_size -= 4; /* safety */
- if (opt_v) printf("DIP: tty: open: IBUF=%d OBUF=%d\n", in_size, out_size);
-
- /* Fetch the current state of the terminal. */
- if (tty_get_state(&tty_saved) < 0) {
- fprintf(stderr, "DIP: tty: open: cannot get current state!\n");
- return(-errno);
- }
-
- (void) memcpy ((char *)&tty_current,
- (char *)&tty_saved, sizeof(struct termios));
-
- /* Fetch the current line discipline of this terminal. */
- if (tty_get_disc(&tty_sdisc) < 0) {
- fprintf(stderr, "DIP: tty: open: cannot get current line disc!\n");
- return(-errno);
- }
- tty_ldisc = tty_sdisc;
-
- /* Put this terminal line in a 8-bit transparent mode. */
- if (tty_set_raw(&tty_current) < 0) {
- fprintf(stderr, "DIP: tty: open: cannot set RAW mode!\n");
- return(-errno);
- }
-
- /* If we are running in MASTER mode, set the default speed. */
- if ((name != NULL) && (tty_set_speed(&tty_current, "38400") != 0)) {
- fprintf(stderr, "DIP: tty: open: cannot set 38400 bps!\n");
- return(-errno);
- }
-
- /* Set up a completely 8-bit clean line. */
- if (tty_set_databits(&tty_current, "8") ||
- tty_set_stopbits(&tty_current, "1") ||
- tty_set_parity(&tty_current, "N")) {
- fprintf(stderr, "DIP: tty: open: cannot set 8N1 mode!\n");
- return(-errno);
- }
-
- /* Set the new line mode. */
- if ((fd = tty_set_state(&tty_current)) < 0) return(fd);
- /* Clear the NDELAY flag now (line is in CLOCAL) */
- flags = fcntl(tty_fd, F_GETFL, 0);
- fcntl(tty_fd, F_SETFL, flags & ~O_NDELAY);
-
- /* OK, all done. Lock this terminal line. */
- return(0);
- }
-