home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / netkit-a.06 / netkit-a / NetKit-A-0.06 / net-tools-1.1.38 / slattach.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  11.6 KB  |  571 lines

  1. /*
  2.  * slattach    A program for handling dialup IP connecions.
  3.  *        This program forces a TTY line to go into a special
  4.  *        terminal line discipline, so that it can be used for
  5.  *        network traffic instead of the regular terminal I/O.
  6.  *
  7.  * Usage:    slattach [-elmnqv] [-s speed] [-p protocol] tty | -
  8.  *
  9.  * Version:    @(#)slattach.c    1.1.29    16/07/94
  10.  *
  11.  * Author:      Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  12.  *        Copyright 1988-1993 MicroWalt Corporation
  13.  *
  14.  * Modified:
  15.  *        Alan Cox, <A.Cox@swansea.ac.uk> , July 16 1994
  16.  *
  17.  *        This program is free software; you can redistribute it
  18.  *        and/or  modify it under  the terms of  the GNU General
  19.  *        Public  License as  published  by  the  Free  Software
  20.  *        Foundation;  either  version 2 of the License, or  (at
  21.  *        your option) any later version.
  22.  */
  23. #include <sys/types.h>
  24. #include <sys/socket.h>
  25. #include <sys/ioctl.h>
  26. #include <sys/stat.h>
  27. #include <stdio.h>
  28. #include <ctype.h>
  29. #include <errno.h>
  30. #include <fcntl.h>
  31. #include <limits.h>
  32. #include <pwd.h>
  33. #include <signal.h>
  34. #include <stdlib.h>          
  35. #include <string.h>
  36. #include <unistd.h>
  37. #include "pathnames.h"
  38. #include "support.h"
  39. #include "version.h"
  40.  
  41.  
  42. #define DEF_PROTO    "cslip"
  43.  
  44.  
  45. char *Release = RELEASE,
  46.      *Version = "@(#) slattach 1.1.29 (16/07/94)";
  47.  
  48.  
  49. struct {
  50.   char    *speed;
  51.   int    code;
  52. } tty_speeds[] = {            /* table of usable baud rates    */
  53.   { "50",    B50    }, { "75",    B75      },    
  54.   { "110",    B110    }, { "300",    B300    },
  55.   { "600",    B600    }, { "1200",    B1200    },
  56.   { "2400",    B2400    }, { "4800",    B4800    },
  57.   { "9600",    B9600    },
  58. #ifdef B14400
  59.   { "14400",    B14400    },
  60. #endif
  61. #ifdef B19200
  62.   { "19200",    B19200    },
  63. #endif
  64. #ifdef B38400
  65.   { "38400",    B38400    },
  66. #endif
  67. #ifdef B57600
  68.   { "57600",    B57600    },
  69. #endif
  70. #ifdef B115200
  71.   { "115200",    B115200    },
  72. #endif
  73.   { NULL,    0    }
  74. };
  75. struct termios    tty_saved,        /* saved TTY device state    */
  76.         tty_current;        /* current TTY device state    */
  77. int        tty_sdisc,        /* saved TTY line discipline    */
  78.         tty_ldisc,        /* current TTY line discipline    */
  79.         tty_fd = -1;        /* TTY file descriptor        */
  80. int        opt_e = 0;        /* "activate only" flag        */
  81. int        opt_l = 0;        /* "lock it" flag        */
  82. int        opt_m = 0;        /* "set RAW mode" flag        */
  83. int        opt_n = 0;        /* "set No Mesg" flag        */
  84. int        opt_q = 0;        /* "quiet" flag            */
  85. int        opt_v = 0;        /* debug flag            */
  86.  
  87.  
  88. /* Disable any messages to the input channel of this process. */
  89. static int
  90. tty_nomesg(int fd)
  91. {
  92.   if (opt_n == 0) return(0);
  93.   return(fchmod(fd, 0600));
  94. }
  95.  
  96.  
  97. /* Lock or unlock a terminal line. */
  98. static int
  99. tty_lock(char *path, int mode)
  100. {
  101.   static char saved_path[PATH_MAX];
  102.   static int saved_lock = 0;
  103.   struct passwd *pw;
  104.   int fd;
  105.  
  106.   /* We do not lock standard input. */
  107.   if ((opt_l == 0) || (path == NULL)) return(0);
  108.  
  109.   if (mode == 1) {    /* lock */
  110.     sprintf(saved_path, "%s/LCK..%s", _PATH_LOCKD, path);
  111.     if ((fd = creat(saved_path, 0644)) < 0) {
  112.         if (errno != EEXIST)
  113.             if (opt_q == 0) fprintf(stderr,
  114.                 "slattach: tty_lock: (%s): %s\n",
  115.                     saved_path, strerror(errno));
  116.         return(-1);
  117.     }
  118.     (void) close(fd);
  119.  
  120.     /* Make sure UUCP owns the lockfile.  Required by some packages. */
  121.     if ((pw = getpwnam(_UID_UUCP)) == NULL) {
  122.         if (opt_q == 0) fprintf(stderr,
  123.             "slattach: tty_lock: UUCP user %s unknown!\n",
  124.                                 _UID_UUCP);
  125.         return(0);    /* keep the lock anyway */
  126.     }
  127.     (void) chown(saved_path, pw->pw_uid, pw->pw_gid);
  128.     saved_lock = 1;
  129.   } else {    /* unlock */
  130.     if (saved_lock != 1) return(0);
  131.     if (unlink(saved_path) < 0) {
  132.         if (opt_q == 0) fprintf(stderr,
  133.             "slattach: tty_unlock: (%s): %s\n", saved_path,
  134.                             strerror(errno));
  135.         return(-1);
  136.     }
  137.     saved_lock = 0;
  138.   }
  139.  
  140.   return(0);
  141. }
  142.  
  143.  
  144. /* Find a serial speed code in the table. */
  145. static int
  146. tty_find_speed(char *speed)
  147. {
  148.   int i;
  149.  
  150.   i = 0;
  151.   while (tty_speeds[i].speed != NULL) {
  152.     if (!strcmp(tty_speeds[i].speed, speed)) return(tty_speeds[i].code);
  153.     i++;
  154.   }
  155.   return(-EINVAL);
  156. }
  157.  
  158.  
  159. /* Set the number of stop bits. */
  160. static int
  161. tty_set_stopbits(struct termios *tty, char *stopbits)
  162. {
  163.   if (opt_v) printf("slattach: tty_set_stopbits: %c\n", *stopbits);
  164.   switch(*stopbits) {
  165.     case '1':
  166.         tty->c_cflag &= ~CSTOPB;
  167.         break;
  168.  
  169.     case '2':
  170.         tty->c_cflag |= CSTOPB;
  171.         break;
  172.  
  173.     default:
  174.         return(-EINVAL);
  175.   }
  176.   return(0);
  177. }
  178.  
  179.  
  180. /* Set the number of data bits. */
  181. static int
  182. tty_set_databits(struct termios *tty, char *databits)
  183. {
  184.   if (opt_v) printf("slattach: tty_set_databits: %c\n", *databits);
  185.   tty->c_cflag &= ~CSIZE;
  186.   switch(*databits) {
  187.     case '5':
  188.         tty->c_cflag |= CS5;
  189.         break;
  190.  
  191.     case '6':
  192.         tty->c_cflag |= CS6;
  193.         break;
  194.  
  195.     case '7':
  196.         tty->c_cflag |= CS7;
  197.         break;
  198.  
  199.     case '8':
  200.         tty->c_cflag |= CS8;
  201.         break;
  202.  
  203.     default:
  204.         return(-EINVAL);
  205.   }
  206.   return(0);
  207. }
  208.  
  209.  
  210. /* Set the type of parity encoding. */
  211. static int
  212. tty_set_parity(struct termios *tty, char *parity)
  213. {
  214.   if (opt_v) printf("slattach: tty_set_parity: %c\n", *parity);
  215.   switch(toupper(*parity)) {
  216.     case 'N':
  217.         tty->c_cflag &= ~(PARENB | PARODD);
  218.         break;  
  219.  
  220.     case 'O':
  221.         tty->c_cflag &= ~(PARENB | PARODD);
  222.         tty->c_cflag |= (PARENB | PARODD);
  223.         break;
  224.  
  225.     case 'E':
  226.         tty->c_cflag &= ~(PARENB | PARODD);
  227.         tty->c_cflag |= (PARENB);
  228.         break;
  229.  
  230.     default:
  231.         return(-EINVAL);
  232.   }
  233.   return(0);
  234. }
  235.  
  236.  
  237. /* Set the line speed of a terminal line. */
  238. static int
  239. tty_set_speed(struct termios *tty, char *speed)
  240. {
  241.   int code;
  242.  
  243.   if (opt_v) printf("slattach: tty_set_speed: %s\n", speed);
  244.   if ((code = tty_find_speed(speed)) < 0) return(code);
  245.   tty->c_cflag &= ~CBAUD;
  246.   tty->c_cflag |= code;
  247.   return(0);
  248. }
  249.  
  250.  
  251. /* Put a terminal line in a transparent state. */
  252. static int
  253. tty_set_raw(struct termios *tty)
  254. {
  255.   int i;
  256.   int speed;
  257.  
  258.   for(i = 0; i < NCCS; i++)
  259.         tty->c_cc[i] = '\0';        /* no spec chr        */
  260.   tty->c_cc[VMIN] = 1;
  261.   tty->c_cc[VTIME] = 0;
  262.   tty->c_iflag = (IGNBRK | IGNPAR);        /* input flags        */
  263.   tty->c_oflag = (0);                /* output flags        */
  264.   tty->c_lflag = (0);                /* local flags        */
  265.   speed = (tty->c_cflag & CBAUD);        /* save current speed    */
  266.   tty->c_cflag = (CRTSCTS | HUPCL | CREAD);    /* UART flags        */
  267.   tty->c_cflag |= speed;            /* restore speed    */
  268.   return(0);
  269. }
  270.  
  271.  
  272. /* Fetch the state of a terminal. */
  273. static int
  274. tty_get_state(struct termios *tty)
  275. {
  276.   if (ioctl(tty_fd, TCGETS, tty) < 0) {
  277.     if (opt_q == 0) fprintf(stderr,
  278.         "slattach: tty_get_state: %s\n", strerror(errno));
  279.     return(-errno);
  280.   }
  281.   return(0);
  282. }
  283.  
  284.  
  285. /* Set the state of a terminal. */
  286. static int
  287. tty_set_state(struct termios *tty)
  288. {
  289.   if (ioctl(tty_fd, TCSETS, tty) < 0) {
  290.     if (opt_q == 0) fprintf(stderr,
  291.         "slattach: tty_set_state: %s\n", strerror(errno));
  292.     return(-errno);
  293.   }
  294.   return(0);
  295. }
  296.  
  297.  
  298. /* Get the line discipline of a terminal line. */
  299. static int
  300. tty_get_disc(int *disc)
  301. {
  302.   if (ioctl(tty_fd, TIOCGETD, disc) < 0) {
  303.     if (opt_q == 0) fprintf(stderr,
  304.         "slattach: tty_get_disc: %s\n", strerror(errno));
  305.     return(-errno);
  306.   }
  307.   return(0);
  308. }
  309.  
  310.  
  311. /* Set the line discipline of a terminal line. */
  312. static int
  313. tty_set_disc(int disc)
  314. {
  315.   if (disc == -1) disc = tty_sdisc;
  316.  
  317.   if (ioctl(tty_fd, TIOCSETD, &disc) < 0) {
  318.     if (opt_q == 0) fprintf(stderr,
  319.         "slattach: tty_set_disc(%d): %s\n", disc, strerror(errno));
  320.     return(-errno);
  321.   }
  322.   return(0);
  323. }
  324.  
  325.  
  326. /* Fetch the name of the network interface attached to this terminal. */
  327. static int
  328. tty_get_name(char *name)
  329. {
  330.   if (ioctl(tty_fd, SIOCGIFNAME, name) < 0) {
  331.     if (opt_q == 0) fprintf(stderr,
  332.         "slattach: tty_get_name: %s\n", strerror(errno));
  333.     return(-errno);
  334.   }
  335.   return(0);
  336. }
  337.  
  338.  
  339. /* Hangup the line. */
  340. static int
  341. tty_hangup(void)
  342. {
  343.   struct termios tty;
  344.  
  345.   tty = tty_current;
  346.   (void) tty_set_speed(&tty, "0");
  347.   if (tty_set_state(&tty) < 0) {
  348.     if (opt_q == 0) fprintf(stderr,
  349.         "slattach: tty_hangup(DROP): %s\n", strerror(errno));
  350.     return(-errno);
  351.   }
  352.  
  353.   (void) sleep(1);
  354.  
  355.   if (tty_set_state(&tty_current) < 0) {
  356.     if (opt_q == 0) fprintf(stderr,
  357.         "slattach: tty_hangup(RAISE): %s\n", strerror(errno));
  358.     return(-errno);
  359.   }
  360.   return(0);
  361. }
  362.  
  363.  
  364. /* Close down a terminal line. */
  365. static int
  366. tty_close(void)
  367. {
  368.   (void) tty_hangup();
  369.   (void) tty_set_disc(tty_sdisc);
  370.   (void) tty_lock(NULL, 0);
  371.   return(0);
  372. }
  373.  
  374.  
  375. /* Open and initialize a terminal line. */
  376. static int
  377. tty_open(char *name, char *speed)
  378. {
  379.   char path[PATH_MAX];
  380.   register char *sp;
  381.   int fd;
  382.  
  383.   /* Try opening the TTY device. */
  384.   if (name != NULL) {
  385.     if ((sp = strrchr(name, '/')) != (char *)NULL) *sp++ = '\0';
  386.       else sp = name;
  387.     sprintf(path, "/dev/%s", sp);
  388.     if ((fd = open(path, O_RDWR)) < 0) {
  389.         if (opt_q == 0) fprintf(stderr,
  390.             "slattach: tty_open(%s, RW): %s\n",
  391.                     path, strerror(errno));
  392.         return(-errno);
  393.     }
  394.     tty_fd = fd;
  395.     if (opt_v) printf("slattach: tty_open: %s (%d) ", path, fd);
  396.   } else {
  397.     tty_fd = 0;
  398.     sp = (char *)NULL;
  399.   }
  400.  
  401.   /* Fetch the current state of the terminal. */
  402.   if (tty_get_state(&tty_saved) < 0) {
  403.     if (opt_q == 0) fprintf(stderr,
  404.         "slattach: tty_open: cannot get current state!\n");
  405.     return(-errno);
  406.   }
  407.   tty_current = tty_saved;
  408.  
  409.   /* Fetch the current line discipline of this terminal. */
  410.   if (tty_get_disc(&tty_sdisc) < 0) {
  411.     if (opt_q == 0) fprintf(stderr,
  412.         "slattach: tty_open: cannot get current line disc!\n");
  413.     return(-errno);
  414.   } 
  415.   tty_ldisc = tty_sdisc;
  416.  
  417.   /* Put this terminal line in a 8-bit transparent mode. */
  418.   if (opt_m == 0) {
  419.     if (tty_set_raw(&tty_current) < 0) {
  420.         if (opt_q == 0) fprintf(stderr,
  421.             "slattach: tty_open: cannot set RAW mode!\n");
  422.         return(-errno);
  423.     }
  424.  
  425.     /* Set the default speed if we need to. */
  426.     if (speed != NULL) {
  427.         if (tty_set_speed(&tty_current, speed) != 0) {
  428.             if (opt_q == 0) fprintf(stderr,
  429.                 "slattach: tty_open: cannot set %s bps!\n",
  430.                                     speed);
  431.             return(-errno);
  432.         }
  433.     }
  434.  
  435.     /* Set up a completely 8-bit clean line. */
  436.     if (tty_set_databits(&tty_current, "8") ||
  437.         tty_set_stopbits(&tty_current, "1") ||
  438.         tty_set_parity(&tty_current, "N")) {
  439.         if (opt_q == 0) fprintf(stderr,
  440.             "slattach: tty_open: cannot set 8N1 mode!\n");
  441.         return(-errno);
  442.       }
  443.  
  444.     /* Set the new line mode. */
  445.     if ((fd = tty_set_state(&tty_current)) < 0) return(fd);
  446.   }
  447.  
  448.   /* OK, line is open.  Do we need to "silence" it? */
  449.   (void) tty_nomesg(tty_fd);
  450.  
  451.   /* OK, all done.  Lock this terminal line. */
  452.   return(tty_lock(sp, 1));
  453. }
  454.  
  455.  
  456. /* Catch any signals. */
  457. static void
  458. sig_catch(int sig)
  459. {
  460.   (void) signal(sig, sig_catch);
  461.   tty_close();
  462.   exit(0);
  463. }
  464.  
  465.  
  466. static void
  467. usage(void)
  468. {
  469.   fprintf(stderr,
  470.     "Usage: slattach [-elmnqv] [-s speed] [-p protocol] tty | -\n");
  471.   exit(1);
  472. }
  473.  
  474.  
  475. int
  476. main(int argc, char *argv[])
  477. {
  478.   char path[128];
  479.   char *speed = NULL;
  480.   char *proto = DEF_PROTO;
  481.   struct hwtype *ht;
  482.   char *sp;
  483.   int s;
  484.  
  485.   strcpy(path, "");
  486.  
  487.   /* Scan command line for any arguments. */
  488.   opterr = 0;
  489.   while ((s = getopt(argc, argv, "elmnp:qs:v")) != EOF) switch(s) {
  490.     case 'e':
  491.         opt_e = 1 - opt_e;
  492.         break;
  493.  
  494.     case 'l':
  495.         opt_l = 1 - opt_l;
  496.         break;
  497.  
  498.     case 'm':
  499.         opt_m = 1 - opt_m;
  500.         break;
  501.  
  502.     case 'n':
  503.         opt_n = 1 - opt_n;
  504.         break;
  505.  
  506.     case 'p':
  507.         proto = optarg;
  508.         break;
  509.  
  510.     case 'q':
  511.         opt_q = 1 - opt_q;
  512.         break;
  513.  
  514.     case 's':
  515.         speed = optarg;
  516.         break;
  517.  
  518.     case 'v':
  519.         opt_v = 1 - opt_v;
  520.         break;
  521.  
  522.     default:
  523.         usage();
  524.   }
  525.  
  526.   /* Check the protocol. */
  527.   if ((ht = get_hwtype(proto)) == NULL) {
  528.     if (opt_q == 0) fprintf(stderr,
  529.         "slattach: unsupportted protocol %s\n", proto);
  530.     return(2);
  531.   }
  532.  
  533.   /* Is a terminal given? */
  534.   if (optind != (argc - 1)) usage();
  535.   strncpy(path, argv[optind], 128);
  536.   if (!strcmp(path, "-")) {
  537.     opt_e = 1;
  538.     sp = NULL;
  539.     if (tty_open(NULL, speed) < 0) return(3);
  540.   } else {
  541.     if ((sp = strchr(path, '/')) != NULL) *sp++ = '\0';
  542.       else sp = path;
  543.     if (tty_open(sp, speed) < 0) return(3);
  544.   }
  545.  
  546.   /* Start the correct protocol. */
  547.   (*ht->activate)(tty_fd);
  548.   if (opt_v == 1) {
  549.     tty_get_name(path);
  550.     printf("%s started", proto);
  551.     if (sp != NULL) printf(" on %s", sp);
  552.     printf("\n");
  553.   }
  554.  
  555.   (void) signal(SIGHUP, sig_catch);
  556.   (void) signal(SIGINT, sig_catch);
  557.   (void) signal(SIGQUIT, sig_catch);
  558.   (void) signal(SIGTERM, sig_catch);
  559.  
  560.   /* Wait until we get killed if hanging on a terminal. */
  561.   if (opt_e == 0) {
  562.     while(1) {
  563.         sleep(60);
  564.     };
  565.  
  566.     tty_close();
  567.   }
  568.  
  569.   exit(0);
  570. }
  571.