home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / init_5 / getty.c < prev    next >
C/C++ Source or Header  |  1993-08-03  |  9KB  |  388 lines

  1. /*
  2.  * getty.c - main code
  3.  * Part of getty(8) for MiNT by Dave Gymer
  4.  * Copyright (C) 1991 D P Gymer. All rights reserved.
  5.  * $Id: getty.c,v 0.1 1992/01/08 15:58:56 dpg Exp dpg $
  6.  * $Log: getty.c,v $
  7.  * Revision 0.1  1992/01/08  15:58:56  dpg
  8.  * Added select(2) call (at least temporarily) so that lines on which this
  9.  * call works will not tie up CPU time.
  10.  * Added support for environmental changes. Still need to add the `ev'
  11.  * capability.
  12.  *
  13.  * Revision 0.0  1991/11/24  19:43:44  dpg
  14.  * First experimental version.
  15.  *
  16.  */
  17.  
  18. #include <ctype.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <ioctl.h>
  22. #include <sgtty.h>
  23. #include <signal.h>
  24. #include <stat.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <termcap.h>
  29. #include <time.h>
  30. #include <unistd.h>
  31.  
  32. #define GETTYTAB "/etc/gettytab"
  33. #ifndef LOGIN
  34. #define LOGIN "/usr/bin/login"
  35. #endif
  36.  
  37. extern int putenv(char *);
  38. extern char **environ;
  39.  
  40. #ifdef atarist
  41. int     __default_mode__ = 1;    /* All binary streams, please. */
  42. #endif
  43.  
  44. struct gettytab {
  45.     struct tchars gt_tchars;
  46.     struct ltchars gt_ltchars;
  47.     struct sgttyb gt_sgttyb;
  48.     char    prompt[32];
  49.     char    banner[80];
  50.     char    hostname[32];
  51.     char    login[FILENAME_MAX];
  52.     char    next[32];
  53. };
  54.  
  55. /* In case we get signalled, eg. alarm. */
  56. static struct sgttyb save_sgttyb;
  57.  
  58. /*
  59.  * This isn't terribly efficient, but then it doesn't have to be, since
  60.  * getty is only here until someone logs on.
  61.  */
  62.  
  63. static int
  64. my_putenv(char *string)
  65. {
  66.     if (!(string = strdup(string)))
  67.         perror("getty: malloc");
  68.     else
  69.         putenv(string);
  70. }
  71.  
  72. /*
  73.  * Take the current hostname and the hostname editing string and
  74.  * produce a new hostname.
  75.  */
  76.  
  77. static void
  78. hostname_edit(char *hostname, const char *edit)
  79. {
  80.     char    oldname[32],
  81.            *name;
  82.  
  83.     strcpy((name = oldname), hostname);
  84.     do {
  85.         switch (*edit) {
  86.         case '@':    /* Add a character. */
  87.             if (*name)
  88.                 *hostname++ = *name++;
  89.             break;
  90.         case '#':    /* Skip a character. */
  91.             if (*name)
  92.                 ++name;
  93.             break;
  94.         default:    /* Includes the null terminator. */
  95.             *hostname++ = *edit;
  96.         }
  97.     } while (*edit++);
  98. }
  99.  
  100. /*
  101.  * Deal with the entry, setting the table entries as required.
  102.  */
  103.  
  104. static void
  105. deal_with_entry(char *entbuf, struct gettytab *buf)
  106. {
  107.     char    sbuf[128],
  108.         termvar[64],
  109.            *s = sbuf;
  110.     int     n;
  111.  
  112.     if (tgetstr("nx", &s))
  113.         strcpy(buf -> next, (s = sbuf));
  114.     else
  115.         *buf -> next = '\0';
  116.     if (tgetstr("hn", &s))
  117.         strcpy(buf -> hostname, (s = sbuf));
  118.     if (tgetstr("he", &s))
  119.         hostname_edit(buf -> hostname, (s = sbuf));
  120.     if (tgetstr("lm", &s))
  121.         strcpy(buf -> prompt, (s = sbuf));
  122.     if (tgetstr("lo", &s))
  123.         strcpy(buf -> login, (s = sbuf));
  124.     if (tgetstr("im", &s))
  125.         strcpy(buf -> banner, (s = sbuf));
  126.     if ((n = tgetnum("to")) != -1)
  127.         alarm(n);
  128.     if (tgetstr("tt", &s)) {
  129.         sprintf(termvar, "TERM=%s", (s = sbuf));
  130.         my_putenv(termvar);
  131.     }
  132. }
  133.  
  134. /*
  135.  * Get a termcap entry from a named file.
  136.  */
  137.  
  138. static int
  139. tgetent_other(char *entbuf, char *type, const char *file)
  140. {
  141.     extern char **environ;
  142.     char  **oldenv = environ,
  143.             envbuf[128],
  144.            *tmpenv[] = {envbuf, 0},
  145.             retval;
  146.  
  147.     sprintf(envbuf, "TERMCAP=%s", file);
  148.     environ = tmpenv;
  149.     retval = tgetent(entbuf, type);
  150.     environ = oldenv;
  151.     return retval;
  152. }
  153.  
  154. /*
  155.  * Find the entry for a particular type and store it in buf.
  156.  * If no entry is found, use some defaults.
  157.  */
  158.  
  159. static void
  160. get_getttytab(char *type, struct gettytab *buf)
  161. {
  162.     char    entbuf[2048];
  163.  
  164.     switch (tgetent_other(entbuf, type, GETTYTAB)) {
  165.     case -1:
  166.     case 0:
  167.         sprintf(entbuf, "getty: non-existant type `%s'\r\n",
  168.             type);
  169.         write(0, entbuf, strlen(entbuf));
  170.         break;
  171.     default:
  172.         deal_with_entry(entbuf, buf);
  173.     }
  174. }
  175.  
  176. /*
  177.  * Format a string.
  178.  * This consists mainly of substituting for %h and the like.
  179.  * BUGS
  180.  *    - doesn't check for the end of the string buffer
  181.  */
  182.  
  183. static char *
  184. fmtstring(const char *s, const struct gettytab *tab)
  185. {
  186.     static char buf[128];
  187.     char   *bp = buf;
  188.  
  189.     while (*s)
  190.         if (*s == '%') {
  191.             switch (*++s) {
  192.             case '\0':
  193.                 goto out;
  194.             case 'h':
  195.                 strcpy(bp, tab -> hostname);
  196.                 while (*bp)
  197.                     ++bp;
  198.                 break;
  199.             case 't':
  200.                 strcpy(bp, ttyname(0));
  201.                 while (*bp)
  202.                     ++bp;
  203.                 break;
  204.             default:
  205.                 *bp = *s;
  206.             }
  207.             ++s;
  208.         } else
  209.             *bp++ = *s++;
  210. out:
  211.     *bp = '\0';
  212.     return buf;
  213. }
  214.  
  215. /*
  216.  * Read the login name.
  217.  * If break is pressed (or what we think is probably break), we try to
  218.  * go to the next entry, by returning zero.
  219.  */
  220.  
  221. static int
  222. read_name(char *name, struct gettytab *buf, int canselect)
  223. {
  224.     char   *s,
  225.             c;
  226.     long fds = 1;
  227.     struct sgttyb tmpsg = buf -> gt_sgttyb;
  228.     extern long select(int, long *, long *, long *, struct timeval *);
  229.  
  230.     tmpsg.sg_flags |= RAW;
  231.     tmpsg.sg_flags &= ~(ECHO | CRMOD);
  232.     stty(0, &tmpsg);
  233.  
  234.     s = fmtstring(buf -> prompt, buf);
  235.     write(0, s, strlen(s));
  236.  
  237.     s = name;
  238.  
  239.     if (canselect)
  240.         select(1, &fds, 0, 0, 0);
  241.     while (read(0, &c, 1) == 1 && c != '\n' && c != '\r') {
  242.         if (!c || c & 128 || c == (buf -> gt_tchars).t_brkc)
  243.             return 0;
  244.         else if (c == (buf -> gt_sgttyb).sg_erase) {
  245.             if (s > name) {
  246.                 --s;
  247.                 write(0, &(buf -> gt_sgttyb).sg_erase, 1);
  248.                 write(0, " ", 1);
  249.                 write(0, &(buf -> gt_sgttyb).sg_erase, 1);
  250.             }
  251.         } else {
  252.             write(0, &c, 1);
  253.             *s++ = c;
  254.         }
  255.     }
  256.  
  257.     /* Did we end with \n or \r? If the latter, we want EOL mapping. */
  258.     if (c == '\n')
  259.         (buf -> gt_sgttyb).sg_flags &= ~CRMOD;
  260.     else
  261.         (buf -> gt_sgttyb).sg_flags |= CRMOD;
  262.  
  263.     *s = '\0';
  264.     write(0, "\r\n", 2);
  265.  
  266.     /* Did the name contain any lowercase letters? Assume not. */
  267.     s = name;
  268.     (buf -> gt_sgttyb).sg_flags &= ~LCASE;
  269.     do
  270.         if (islower(*s)) {
  271.             (buf -> gt_sgttyb).sg_flags |= LCASE;
  272.             break;
  273.         }
  274.     while (*s++);
  275.  
  276.     return 1;
  277. }
  278.  
  279. static void
  280. do_alarm(long sig)
  281. {
  282.     const char *s = "Connection timed out.\r\n";
  283.  
  284.     ioctl(0, TIOCSETP, &save_sgttyb);
  285.     write(0, s, strlen(s));
  286.     exit(1);
  287. }
  288.  
  289. int
  290. main(int argc, char **argv)
  291. {
  292.     struct gettytab tab;
  293.     char   *type = 0,
  294.            *tty,
  295.             buf[256];
  296.     int     fd,
  297.         canselect,
  298.             banner_flag = 1;
  299.     struct stat info;
  300.     extern int gethostname(char *, int);
  301.     extern int execle(const char *, const char *,...);
  302.     extern char *ttyname(int);
  303.  
  304.     ioctl(0, TIOCGETP, &save_sgttyb);
  305.     signal(SIGALRM, do_alarm);
  306.  
  307.     /* Check for arguments. We ignore all but the last two. */
  308.     if (argc > 2) {        /* a tty was specified */
  309.         close(0);
  310.         fd = open((tty = argv[--argc]), O_RDWR);
  311.         if (fd) {
  312.             dup2(fd, 0);
  313.             close(fd);
  314.             fd = 0;
  315.         }
  316.     } else
  317.         tty = ttyname(fd = 0);
  318.  
  319.     if (argc > 1)        /* a type was specified */
  320.         type = argv[--argc];
  321.  
  322.     if (fd < -1 || fd > 2)
  323.         close(fd);
  324.  
  325. #ifdef atarist
  326.     dup2(fd, -1);        /* Controlling terminal. */
  327. #endif
  328.     dup2(fd, 1);
  329.     dup2(fd, 2);
  330.  
  331.     /* Set up some defaults for the terminal type. */
  332.     ioctl(0, TIOCGETP, &tab.gt_sgttyb);
  333.     ioctl(0, TIOCGETC, &tab.gt_tchars);
  334.     ioctl(0, TIOCGLTC, &tab.gt_ltchars);
  335.     strcpy(tab.prompt, "login: ");
  336.     strcpy(tab.banner, "%h running MiNT: line %t");
  337.     strcpy(tab.login, LOGIN);
  338.     *tab.next = '\0';
  339.     gethostname(tab.hostname, 32);
  340.  
  341.     /* Get any default entries in the table. */
  342.     get_getttytab("default", &tab);
  343.  
  344.     /* Fselect(2) does not yet work on BIOS devices except the console. */
  345.     /* Probably when this works right, we won't need select anyway!!! */
  346.     if (!strcmp("/dev/console", tty) ||
  347.         !fstat(0, &info) && info.st_mode & S_IFMT != S_IFCHR)
  348.         canselect = 1;
  349.     else
  350.         canselect = 0;
  351.  
  352.     /* Set up terminal type and read name until happy. */
  353.     for (;;) {
  354.         if (type && *type) {    /* Type to look up? */
  355.             get_getttytab(type, &tab);
  356.             ioctl(0, TIOCSETP, &tab.gt_sgttyb);
  357.             ioctl(0, TIOCSETC, &tab.gt_tchars);
  358.             ioctl(0, TIOCSLTC, &tab.gt_ltchars);
  359.         }
  360.         if (banner_flag) {    /* Print the banner? */
  361.             char   *s;
  362.  
  363.             s = fmtstring(tab.banner, &tab);
  364.             write(0, s, strlen(s));
  365.             banner_flag = 0;
  366.         }
  367.         if (!read_name(buf, &tab, canselect)) {    /* Try next entry. */
  368.             if (tab.next)
  369.                 type = tab.next;
  370.             else
  371.                 type = 0;
  372.             banner_flag = 1;
  373.         } else if (*buf)/* Got a name. */
  374.             break;
  375.     }
  376.     ioctl(0, TIOCSETP, &tab.gt_sgttyb);    /* May have changed some. */
  377.  
  378.     /* Call login. If LOGIN is in use, preserve $TERM. */
  379.     if (strcmp(LOGIN, tab.login))
  380.         execle(tab.login, tab.login, buf, (char *) 0, environ);
  381.     else
  382.         execle(tab.login, tab.login, "-p", buf, (char *) 0, environ);
  383.     sprintf(buf, "getty: can't exec (%s) - %s\r\n", tab.login,
  384.         errno > 0 && errno <= sys_nerr ? strerror(errno) : "???");
  385.     write(0, buf, strlen(buf));
  386.     return 1;
  387. }
  388.