home *** CD-ROM | disk | FTP | other *** search
- /*
- * slattach A program for handling dialup IP connecions.
- * This program forces a TTY line to go into a special
- * terminal line discipline, so that it can be used for
- * network traffic instead of the regular terminal I/O.
- *
- * Usage: slattach [-ehlmnqv] [-c cmd] [-s speed] [-p protocol] tty | -
- *
- * Version: @(#)slattach.c 1.1.30 03/01/95
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Copyright 1988-1993 MicroWalt Corporation
- *
- * Modified:
- * Alan Cox, <A.Cox@swansea.ac.uk> , July 16 1994
- * Miquel van Smoorenburg, <miquels@drinkel.ow.org>, October 1994
- * George Shearer, <gshearer@one.net>, January 3, 1995
- *
- * 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 <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <pwd.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include "pathnames.h"
- #include "support.h"
- #include "version.h"
-
- #define DEF_PROTO "cslip"
-
-
- char *Release = RELEASE,
- *Version = "@(#) slattach 1.1.79 (10-Jan-95)";
-
-
- struct {
- char *speed;
- int code;
- } tty_speeds[] = { /* table of usable baud rates */
- { "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 }
- };
- struct termios tty_saved, /* saved TTY device state */
- tty_current; /* current TTY device state */
- int tty_sdisc, /* saved TTY line discipline */
- tty_ldisc, /* current TTY line discipline */
- tty_fd = -1; /* TTY file descriptor */
- int opt_c = 0; /* "command" to run at exit */
- int opt_e = 0; /* "activate only" flag */
- int opt_h = 0; /* "hangup" on carrier loss */
- int opt_l = 0; /* "lock it" flag */
- int opt_m = 0; /* "set RAW mode" flag */
- int opt_n = 0; /* "set No Mesg" flag */
- int opt_q = 0; /* "quiet" flag */
- int opt_d = 0; /* debug flag */
- int opt_v = 0; /* Verbose flag */
-
- /* Disable any messages to the input channel of this process. */
- static int
- tty_nomesg(int fd)
- {
- if (opt_n == 0) return(0);
- return(fchmod(fd, 0600));
- }
-
-
- /* Lock or unlock a terminal line. */
- static int
- tty_lock(char *path, int mode)
- {
- static char saved_path[PATH_MAX];
- static int saved_lock = 0;
- struct passwd *pw;
- int fd;
-
- /* We do not lock standard input. */
- if ((opt_l == 0) || (path == NULL)) return(0);
-
- if (mode == 1) { /* lock */
- sprintf(saved_path, "%s/LCK..%s", _PATH_LOCKD, path);
- if ((fd = creat(saved_path, 0644)) < 0) {
- if (errno != EEXIST)
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_lock: (%s): %s\n",
- saved_path, strerror(errno));
- return(-1);
- }
- (void) close(fd);
-
- /* Make sure UUCP owns the lockfile. Required by some packages. */
- if ((pw = getpwnam(_UID_UUCP)) == NULL) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: 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 { /* unlock */
- if (saved_lock != 1) return(0);
- if (unlink(saved_path) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_unlock: (%s): %s\n", saved_path,
- strerror(errno));
- 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_d) printf("slattach: 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_d) printf("slattach: 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_d) printf("slattach: 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_d) printf("slattach: tty_set_speed: %s\n", speed);
- if ((code = tty_find_speed(speed)) < 0) return(code);
- 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); /* 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) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: 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) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_set_state: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Get the line discipline of a terminal line. */
- static int
- tty_get_disc(int *disc)
- {
- if (ioctl(tty_fd, TIOCGETD, disc) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_get_disc: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Set the line discipline of a terminal line. */
- static int
- tty_set_disc(int disc)
- {
- if (disc == -1) disc = tty_sdisc;
-
- if (ioctl(tty_fd, TIOCSETD, &disc) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_set_disc(%d, %d): %s\n", tty_fd,
- disc, strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Fetch the name of the network interface attached to this terminal. */
- static int
- tty_get_name(char *name)
- {
- if (ioctl(tty_fd, SIOCGIFNAME, name) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_get_name: %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Hangup the line. */
- static int
- tty_hangup(void)
- {
- struct termios tty;
-
- tty = tty_current;
- (void) tty_set_speed(&tty, "0");
- if (tty_set_state(&tty) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_hangup(DROP): %s\n", strerror(errno));
- return(-errno);
- }
-
- (void) sleep(1);
-
- if (tty_set_state(&tty_current) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_hangup(RAISE): %s\n", strerror(errno));
- return(-errno);
- }
- return(0);
- }
-
-
- /* Close down a terminal line. */
- static int
- tty_close(void)
- {
- (void) tty_set_disc(tty_sdisc);
- (void) tty_hangup();
- (void) tty_lock(NULL, 0);
- return(0);
- }
-
-
- /* Open and initialize a terminal line. */
- static int
- tty_open(char *name, char *speed)
- {
- char path[PATH_MAX];
- register char *sp;
- int fd;
-
- /* 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)) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_open(%s, RW): %s\n",
- path, strerror(errno));
- return(-errno);
- }
- tty_fd = fd;
- if (opt_d) printf("slattach: tty_open: %s (%d) ", path, fd);
- } else {
- tty_fd = 0;
- sp = (char *)NULL;
- }
-
- /* Fetch the current state of the terminal. */
- if (tty_get_state(&tty_saved) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_open: cannot get current state!\n");
- return(-errno);
- }
- tty_current = tty_saved;
-
- /* Fetch the current line discipline of this terminal. */
- if (tty_get_disc(&tty_sdisc) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: 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 (opt_m == 0) {
- if (tty_set_raw(&tty_current) < 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_open: cannot set RAW mode!\n");
- return(-errno);
- }
-
- /* Set the default speed if we need to. */
- if (speed != NULL) {
- if (tty_set_speed(&tty_current, speed) != 0) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_open: cannot set %s bps!\n",
- speed);
- 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")) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: tty_open: cannot set 8N1 mode!\n");
- return(-errno);
- }
-
- /* Set the new line mode. */
- if ((fd = tty_set_state(&tty_current)) < 0) return(fd);
- }
-
- /* OK, line is open. Do we need to "silence" it? */
- (void) tty_nomesg(tty_fd);
-
- /* OK, all done. Lock this terminal line. */
- return(tty_lock(sp, 1));
- }
-
-
- /* Catch any signals. */
- static void
- sig_catch(int sig)
- {
- (void) signal(sig, sig_catch);
- tty_close();
- exit(0);
- }
-
-
- static void
- usage(void)
- {
- fprintf(stderr,
- "Usage: slattach [-ehlmnqv] [-c cmd] [-s speed] [-p protocol] tty | -\n");
- exit(1);
- }
-
-
- int
- main(int argc, char *argv[])
- {
- char path[128];
- char buff[128];
- char *speed = NULL;
- char *proto = DEF_PROTO;
- char *extcmd = (char *)0;
- struct hwtype *ht;
- char *sp;
- int s;
-
- strcpy(path, "");
-
- /* Scan command line for any arguments. */
- opterr = 0;
- while ((s = getopt(argc, argv, "c:ehlmnp:qs:vd")) != EOF) switch(s) {
- case 'c':
- extcmd = optarg;
- break;
-
- case 'e':
- opt_e = 1 - opt_e;
- break;
-
- case 'h':
- opt_h = 1 - opt_h;
- break;
-
- case 'l':
- opt_l = 1 - opt_l;
- break;
-
- case 'm':
- opt_m = 1 - opt_m;
- break;
-
- case 'n':
- opt_n = 1 - opt_n;
- break;
-
- case 'p':
- proto = optarg;
- break;
-
- case 'q':
- opt_q = 1 - opt_q;
- break;
-
- case 's':
- speed = optarg;
- break;
-
- case 'd':
- opt_d = 1 - opt_d;
- break;
-
- case 'v':
- opt_v = 1 - opt_v;
- break;
-
- default:
- usage();
- }
-
- /* Check the protocol. */
- if ((ht = get_hwtype(proto)) == NULL && strcmp(proto, "tty")) {
- if (opt_q == 0) fprintf(stderr,
- "slattach: unsupported protocol %s\n", proto);
- return(2);
- }
- if (ht == NULL) opt_m++;
-
- /* Is a terminal given? */
- if (optind != (argc - 1)) usage();
- strncpy(path, argv[optind], 128);
- if (!strcmp(path, "-")) {
- opt_e = 1;
- sp = NULL;
- if (tty_open(NULL, speed) < 0) return(3);
- } else {
- if ((sp = strrchr(path, '/')) != NULL) *sp++ = '\0';
- else sp = path;
- if (tty_open(sp, speed) < 0) return(3);
- }
-
- /* Start the correct protocol. */
- if (ht == NULL) {
- tty_sdisc = N_TTY;
- tty_close();
- return(0);
- }
- (*ht->activate)(tty_fd);
- if (opt_v == 1) {
- tty_get_name(buff);
- printf("%s started", proto);
- if (sp != NULL) printf(" on %s", sp);
- printf(" interface %s\n", buff);
- }
-
- (void) signal(SIGHUP, sig_catch);
- (void) signal(SIGINT, sig_catch);
- (void) signal(SIGQUIT, sig_catch);
- (void) signal(SIGTERM, sig_catch);
-
- /* Wait until we get killed if hanging on a terminal. */
- if (opt_e == 0) {
- while(1) {
- if(opt_h == 1) { /* hangup on carrier loss */
- int n = 0;
-
- ioctl(tty_fd, TIOCMGET, &n);
- if(!(n & TIOCM_CAR))
- break;
- sleep(15);
- }
- else
- sleep(60);
- };
-
- tty_close();
- if(extcmd!=(char *)0) /* external command on exit */
- system(extcmd);
- }
-
- exit(0);
- }
-