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