home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / advise / part01 / advise.c next >
Encoding:
C/C++ Source or Header  |  1992-02-23  |  15.3 KB  |  854 lines

  1. /* Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com)
  2.  
  3. This file is part of advise.
  4.  
  5. advise is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY.  No author or distributor
  7. accepts responsibility to anyone for the consequences of using it
  8. or for whether it serves any particular purpose or works at all,
  9. unless he says so in writing.  Refer to the advise General Public
  10. License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. advise, but only under the conditions described in the
  14. advise General Public License.   A copy of this license is
  15. supposed to have been given to you along with advise so you
  16. can know your rights and responsibilities.  It should be in a
  17. file named COPYING.  Among other things, the copyright notice
  18. and this notice must be preserved on all copies.  */
  19.  
  20. /*
  21. ** Author:    Keith Gabryelski    (ag@amix.commodore.com)
  22. */
  23.  
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include <stropts.h>
  32. #include <poll.h>
  33. #include <sys/stream.h>
  34. #include <errno.h>
  35. #include <utmp.h>
  36. #include <pwd.h>
  37. #include <termios.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40. #include "advise.h"
  41.  
  42. #ifdef sun
  43. extern int optind;
  44.  
  45. #ifndef CTRL
  46. #define    CTRL(c)    ((c)&037)
  47. #endif /* !CTRL */
  48.  
  49. #ifndef EUNATCH
  50. #define EUNATCH ENOPROTOOPT
  51. #endif /* ! EUNATCH */
  52.  
  53. #endif /* sun */
  54.  
  55. extern char *optarg;
  56.  
  57. #define max(a,b) ((a)>(b)?(a):(b))
  58.  
  59. static struct module_list
  60. {
  61.     char *name;            /* name of module */
  62.     struct module_list *next;    /* next module to be pushed */
  63. } advise_module_list =
  64. {
  65.     ADVMODNAME, NULL,
  66. };
  67.  
  68. #ifdef __STDC__
  69. #define PR_(x)    x
  70. #else
  71. #define PR_(x)    ()
  72. #endif /* __STDC__ */
  73.  
  74. static void usage PR_( (void) ), advise PR_( (char *) );
  75. static char *strchar PR_( (char) );
  76. static struct module_list *list_modules PR_( (int, char *));
  77.  
  78. static int allow_deny_p, allow_deny;
  79. static int allow_advise_p, allow_advise;
  80. static int error_flag;
  81. static int secret, spy, reverse;
  82. static int meta_character = '~';
  83. static char *progname;
  84. static char *module = "ldterm";
  85.  
  86. #ifdef sun
  87.  
  88. #ifndef __STDC__
  89. /*
  90.  * strerror - map error number to descriptive string
  91.  * (stolen from cnews/libfake/strerror.c)
  92.  *
  93.  */
  94. static char *
  95. strerror(errnum)
  96. int errnum;
  97. {
  98.     extern int sys_nerr;
  99.     extern char *sys_errlist[];
  100.  
  101.     if (errnum > 0 && errnum < sys_nerr)
  102.         return(sys_errlist[errnum]);
  103.     else if (errnum != 0)
  104.         return("unknown error");
  105.     else
  106.         return("no details given");
  107. }
  108. #endif /* ! __STDC__ */
  109.  
  110. static int utmpfd=-1;
  111.  
  112. void
  113. endutent(
  114. #ifdef __STDC__
  115.     void
  116. #endif /* __STDC__ */
  117.     )
  118. {
  119.     if(utmpfd!=-1) close(utmpfd);
  120.     utmpfd=-1;
  121. }
  122.  
  123. void
  124. setutent(
  125. #ifdef __STDC__
  126.     void
  127. #endif /* __STDC__ */
  128.     )
  129. {
  130.     endutent();
  131.     utmpfd=open("/etc/utmp", O_RDONLY);
  132. }
  133.  
  134. struct utmp *
  135. getutent(
  136. #ifdef __STDC__
  137.     void
  138. #endif /* __STDC__ */
  139.     )
  140. {
  141.     static struct utmp ut;
  142.     int ret;
  143.  
  144.     if(utmpfd==-1) return(NULL);
  145.     do {
  146.         if(read(utmpfd, &ut, sizeof(ut)) != sizeof(ut)) return(NULL);
  147.     } while(nonuser(ut));
  148.  
  149.     return(&ut);
  150. }
  151.  
  152. struct utmp *
  153. #ifdef __STDC__
  154. getutline(struct utmp *ut)
  155. #else
  156. getutline(ut)
  157. struct utmp *ut;
  158. #endif /* __STDC__ */
  159. {
  160.     struct utmp *utm;
  161.  
  162.     while(utm=getutent())
  163.         if(!strncmp(utm->ut_line, ut->ut_line)) return(utm);
  164.  
  165.     return(NULL);
  166. }
  167. #endif /* sun */
  168.  
  169. int
  170. #ifdef __STDC__
  171. main(int argc, char **argv)
  172. #else
  173. main(argc, argv)
  174. char **argv;
  175. #endif /* __STDC__ */
  176. {
  177.     int c, error=0;
  178.     struct termios termios;
  179.     struct module_list *modules;
  180.  
  181.     progname = *argv;
  182.  
  183.     while((c = getopt(argc, argv, "ADM:Sardm:s?")) != EOF)
  184.     {
  185.     switch(c)
  186.     {
  187.     case 's':
  188.         spy++;
  189.         break;
  190.  
  191.     case 'r':
  192.         if (!getuid())
  193.         reverse++;
  194.         else
  195.         {
  196.         (void) fprintf(stderr, "%s: -r option only available to the super user\n", progname);
  197.         error_flag++;
  198.         }
  199.         break;
  200.  
  201.     case 'S':
  202.         if (!getuid())
  203.         secret++;
  204.         else
  205.         {
  206.         (void) fprintf(stderr, "%s: -S option only available to the super user\n", progname);
  207.         error_flag++;
  208.         }
  209.         break;
  210.  
  211.     case 'a':
  212.         allow_deny_p++;
  213.         allow_deny=ADVISE_ALLOW;
  214.         allow_advise_p++;
  215.         allow_advise++;
  216.         break;
  217.  
  218.     case 'd':
  219.         allow_advise_p++;
  220.         allow_advise=0;
  221.         break;
  222.  
  223.     case 'A':
  224.         allow_deny_p++;
  225.         allow_deny=ADVISE_ALLOW;
  226.         break;
  227.  
  228.     case 'D':
  229.         allow_deny_p++;
  230.         allow_deny=ADVISE_DENY;
  231.         break;
  232.  
  233.     case 'm':
  234.         meta_character = optarg[0];
  235.         break;
  236.  
  237.     case 'M':
  238.         module = optarg;
  239.         break;
  240.  
  241.     case '?':
  242.         error_flag++;
  243.         break;
  244.     }
  245.  
  246.     if (error_flag)
  247.     {
  248.         usage();
  249.     }
  250.     }
  251.  
  252.     if (allow_advise_p)
  253.     {
  254.     int status = ioctl(0, ADVISE_STATUS, &status);
  255.  
  256.     if (allow_advise && status)
  257.     {
  258.         int advise_module_pushed = 0;
  259.  
  260.         /* Push advise module on stream */
  261.         (void) ioctl(0, TCGETS, &termios);
  262.  
  263.         modules = list_modules(0, module);
  264.  
  265.         advise_module_list.next = modules;
  266.  
  267.         for (modules = &advise_module_list;
  268.          modules != NULL;
  269.          modules = modules->next)
  270.         {
  271.  
  272.         if (!strcmp(modules->name, ADVMODNAME))
  273.         {
  274.             if (advise_module_pushed)
  275.             continue;
  276.  
  277.             advise_module_pushed = 1;
  278.         }
  279.  
  280.         if (ioctl(0, I_PUSH, modules->name))
  281.         {
  282.             (void) fprintf(stderr, "%s: Couldn't I_PUSH: %s (%s).\n",
  283.                    progname, modules->name, strerror(errno));
  284.             error++;
  285.         }
  286.         }
  287.  
  288.         (void) ioctl(0, TCSETS, &termios);
  289.     }
  290.  
  291.     if (!allow_advise && !status)
  292.     {
  293.         (void) ioctl(0, TCGETS, &termios);
  294.  
  295.         modules = list_modules(0, ADVMODNAME);
  296.  
  297.         while (modules != NULL)
  298.         {
  299.         if (strcmp(modules->name, ADVMODNAME))
  300.         {
  301.             if (ioctl(0, I_PUSH, modules->name))
  302.             {
  303.             (void) fprintf(stderr,
  304.                        "%s: Couldn't I_PUSH: %s (%s).\n",
  305.                        progname, modules->name,
  306.                        strerror(errno));
  307.             error++;
  308.             }
  309.         }
  310.  
  311.         modules = modules->next;
  312.         }
  313.  
  314.         (void) ioctl(0, TCSETS, &termios);
  315.     }
  316.  
  317.     if (!allow_deny_p)
  318.         return error ? 1 : 0;
  319.     }
  320.  
  321.     if (allow_deny_p)
  322.     {
  323.     if (ioctl(0, allow_deny, 0))
  324.     {
  325.         if (errno == EINVAL)
  326.         {
  327.         (void) fprintf(stderr, "%s: module \"%s\" not in stream.\n",
  328.                    progname, ADVMODNAME);
  329.         }
  330.         else
  331.         {
  332.         (void) fprintf(stderr, "%s: Couldn't set advisory mode (%s).\n",
  333.                    progname, strerror(errno));
  334.         }
  335.  
  336.         return 1;
  337.     }
  338.  
  339.     goto advstat;
  340.     }
  341.  
  342.     /* All switches have been handled */
  343.  
  344.     argc -= optind;
  345.     argv += optind;
  346.  
  347.     if (argc > 1)
  348.     {
  349.     usage();
  350.     }
  351.  
  352.     if (argc == 0)
  353.     {
  354.     int retval, status;
  355.  
  356. advstat:
  357.     /*
  358.     ** Status of advise.
  359.     */
  360.  
  361.     retval = ioctl(0, ADVISE_STATUS, &status);
  362. #if !defined(M_COPYOUT) && !defined(sun)
  363.     status = !retval;
  364. #endif /* n M_COPYOUT */
  365.  
  366.     if (retval)
  367.     {
  368.         printf("Module \"%s\" not pushed on stream.\n", ADVMODNAME);
  369.     }
  370.     else
  371.     {
  372.         printf("Advise access %s\n", status ? "allowed" : "denied");
  373.     }
  374.  
  375.     return 0;
  376.     }
  377.  
  378.     advise(*argv);
  379.  
  380.     return 0;
  381. }
  382.  
  383. static void
  384. usage(
  385. #ifdef __STDC__
  386.     void
  387. #endif /* __STDC__ */
  388.     )
  389. {
  390.     (void) fprintf(stderr, "usage: %s [-ADad?] [-M module] | [-Ssr] [-m char] [ device | username ]\n",
  391.            progname);
  392.     exit(1);
  393. }
  394.  
  395. struct termios termios, oldtermios;
  396.  
  397. void restoretermios(sig)
  398. {
  399.     (void) ioctl(0, TCSETS, &oldtermios);
  400.     exit(0);
  401. }
  402.  
  403. static void
  404. #ifdef __STDC__
  405. advise(char *who)
  406. #else
  407. advise(who)
  408. char *who;
  409. #endif /* __STDC__ */
  410. {
  411.     int ret, fd, metad=0;
  412.     char buf[1024], *device=NULL, *devname, *login_name, *tty_name;
  413.     struct pollfd pfds[2];
  414.     struct stat stbuf;
  415.     struct utmp *ut, uts;
  416.     char username[sizeof(ut->ut_name) + 1];
  417.  
  418.     username[0] = '\0';
  419.  
  420.     if (*who == '/') /* full path name */
  421.     device = who;
  422.     else
  423.     {
  424.     /* Either this is /dev/ + who OR a username */
  425.  
  426.     setutent();
  427.  
  428.     while ((ut = getutent()) != NULL)
  429.     {
  430.         if (
  431. #ifdef USER_PROCESS
  432.         (ut->ut_type==USER_PROCESS) &&
  433. #endif /* USER_PROCESS */
  434.         (!strncmp(who, ut->ut_name, sizeof(ut->ut_name))))
  435.         {
  436.         if(device) free(device);
  437.         device = (char *)malloc(sizeof("/dev/") +
  438.                     sizeof(ut->ut_line));
  439.  
  440.         if (device == NULL)
  441.         {
  442.             (void) fprintf(stderr,
  443.                 "%s: malloc failed (Out of Memory)\n",
  444.                 progname);
  445.  
  446.             exit(1);
  447.         }
  448.  
  449.         strcpy(device, "/dev/");
  450.         strncat(device, ut->ut_line, sizeof(ut->ut_line));
  451.         device[sizeof("/dev/")+sizeof(ut->ut_line)] = '\0';
  452.  
  453.         strncpy(username, ut->ut_name, sizeof(ut->ut_name));
  454.         username[sizeof(ut->ut_name)] = '\0';
  455.         if(!strcmp(device, ttyname(0))) continue;
  456.         break;
  457.         }
  458.     }
  459.  
  460.     if (device == NULL) /* Is /dev/ + who */
  461.     {
  462.         device = (char *)malloc(sizeof("/dev/") + strlen(who));
  463.  
  464.         if (device == NULL)
  465.         {
  466.         (void) fprintf(stderr, "%s: malloc failed (Out of Memory)\n",
  467.                 progname);
  468.  
  469.         exit(1);
  470.         }
  471.  
  472.         strcpy(device, "/dev/");
  473.         strcat(device, who);
  474.     }
  475.  
  476.     endutent();
  477.     }
  478.  
  479.     devname = device + sizeof("/dev/") - 1;
  480.  
  481.     if (username[0] == '\0')
  482.     {
  483.     setutent();
  484.  
  485.     strncpy(uts.ut_line, devname, sizeof(uts.ut_line));
  486.  
  487.     if ((ut = getutline(&uts)) != NULL)
  488.     {
  489.         strncpy(username, ut->ut_name, sizeof(ut->ut_name));
  490.         username[sizeof(ut->ut_name)] = '\0';
  491.     }
  492.     else
  493.     {
  494.         strcpy(username, "unknown");
  495.     }
  496.  
  497.     endutent();
  498.     }
  499.  
  500.     if(!strcmp(device, ttyname(0)))
  501.     {
  502.     (void) fprintf(stderr, "%s: Can't advise yourself!\n", progname);
  503.     exit(1);
  504.     }
  505.  
  506.     if (stat(device, &stbuf) < 0)
  507.     {
  508.     if (errno == ENOENT)
  509.     {
  510.         if(*who=='/') (void) fprintf(stderr, "%s: no advisee device \"%s\"\n", progname, device);
  511.         else (void) fprintf(stderr, "%s: unknown user \"%s\" or no advisee device \"%s\"\n", progname, who, device);
  512.     }
  513.     else
  514.     {
  515.         (void) fprintf(stderr,
  516.                "%s: Couldn't stat() advisee device: %s (%s)\n",
  517.                progname, device, strerror(errno));
  518.     }
  519.     exit(1);
  520.     }
  521.  
  522.     if ((fd = open("/dev/advise", O_RDWR|O_NONBLOCK)) < 0)
  523.     {
  524.     (void) fprintf(stderr,
  525.            "%s: Couldn't open advisory device: /dev/advise (%s)\n",
  526.            progname, strerror(errno));
  527.     exit(1);
  528.     }
  529.     setuid(getuid());
  530.  
  531.     if (ioctl(fd, reverse?ADVISE_SETADVISEERD:ADVISE_SETADVISEEWR, 
  532. #ifdef sun
  533.     &
  534. #endif /* sun */
  535.     stbuf.st_rdev))
  536.     {
  537.     if (errno == EUNATCH)
  538.     {
  539.         (void) fprintf(stderr,
  540.                "%s: module \"%s\" not in place for %s\n",
  541.                progname, ADVMODNAME, device);
  542.     } else if (errno == EACCES)
  543.     {
  544.         (void) fprintf(stderr, "%s: Permission denied\n", progname);
  545.     } else
  546.     {
  547.         (void) fprintf(stderr,
  548.                "%s: Couldn't set advisee: %s (%lu, %lu) (%s)\n",
  549.             progname, device,
  550. #ifdef sun
  551.             major(stbuf.st_rdev), minor(stbuf.st_rdev),
  552. #else
  553.             ((stbuf.st_rdev >> 16) &0xFFFF), (stbuf.st_rdev&0xFFFF),
  554. #endif /* sun */
  555.             strerror(errno));
  556.     }
  557.     exit(1);
  558.     }
  559.  
  560.     if (!secret)
  561.     {
  562.     char *str;
  563.     struct passwd *pt;
  564.  
  565.     if ((login_name = getlogin()) == NULL)
  566.     {
  567.         pt = getpwuid(getuid());
  568.  
  569.         if (pt == NULL || pt->pw_name == NULL)
  570.         {
  571.         login_name = "somebody";
  572.         }
  573.         else
  574.         {
  575.         login_name = pt->pw_name;
  576.         }
  577.     }
  578.  
  579.     if ((tty_name = ttyname(2)) != NULL)
  580.     {
  581.         if (!strncmp(tty_name, "/dev/", sizeof("/dev/")-1))
  582.         tty_name += sizeof("/dev/")-1;
  583.     }
  584.     else
  585.         tty_name = "somewhere";
  586.  
  587.     str = malloc(strlen(login_name) + strlen(tty_name) +
  588.              sizeof("[: advising :]\n\r") + strlen(username) +
  589.              strlen(devname));
  590.  
  591.     if (str)
  592.     {
  593.         struct advise_message m;
  594.         struct strbuf ctl, data;
  595.  
  596.         m.type = ADVISE_READDATA;
  597.  
  598.         ctl.len = sizeof(m);
  599.         ctl.buf = (void *)&m;
  600.  
  601.         sprintf(str, "[%s:%s %s %s:%s]\n\r", login_name,
  602.             tty_name, spy ? "spying" : "advising", username, devname);
  603.  
  604.         data.len = strlen(str);
  605.         data.buf = str;
  606.  
  607.         (void) putmsg(fd, &ctl, &data, 0);
  608.  
  609.         free(str);
  610.     }
  611.     }
  612.  
  613.  
  614.     (void) ioctl(0, TCGETS, &termios);
  615.  
  616.     oldtermios = termios;
  617.     signal(SIGTERM, restoretermios);
  618.     termios.c_oflag &= ~OPOST;
  619.  
  620.     if (!spy)
  621.     {
  622.     termios.c_cc[VMIN] = 1;
  623.     termios.c_cc[VTIME] = 0;
  624.     termios.c_lflag &= ~(ISIG|ICANON|ECHO);
  625.     } else signal(SIGINT, restoretermios);
  626.     (void) ioctl(0, TCSETS, &termios);
  627.  
  628.     pfds[0].fd = fd;
  629.     pfds[0].events = POLLIN;
  630.  
  631.     pfds[1].fd = 0;
  632.     pfds[1].events = POLLIN;
  633.  
  634.     for (;;)
  635.     {
  636.     if (poll(pfds, spy?1:2, INFTIM) < 0)
  637.         continue;
  638.  
  639.     if ((pfds[0].revents&POLLHUP) != 0) /* module removed */
  640.     {
  641.         (void) ioctl(0, TCSETS, &oldtermios);
  642.         exit(0);
  643.     }
  644.     if ((pfds[0].revents&POLLIN) != 0) /* data from advisee ready */
  645.     {
  646.         if ((ret = read(fd, buf, sizeof(buf))) > 0)
  647.         write(1, buf, ret);
  648.     }
  649.  
  650.     if (!spy && ((pfds[1].revents&POLLIN) != 0)) /* data from advisor ready */
  651.     {
  652.         if ((ret = read(0, buf, sizeof(buf))) > 0)
  653.         {
  654.             register int i;
  655.             register char *p = buf, *pp=buf;
  656.  
  657.             for (i=0; i < ret; ++i, p++)
  658.             {
  659.             if (metad)
  660.             {
  661.                 if (metad == 2)
  662.                 {
  663.                 meta_character = *p;
  664.                 printf("The meta character is now: %s\n",
  665.                        strchar(meta_character));
  666.                 pp++;
  667.                 metad = 0;
  668.                 continue;
  669.                 }
  670.  
  671.                 switch (*p)
  672.                 {
  673.                 case '=':
  674.                 metad=2;
  675.                 pp++;
  676.                 break;
  677.  
  678.                 case '?':
  679.                 {
  680.                 char *escstr = strchar(meta_character);
  681.  
  682.                 printf("Help for meta character <%s>:\n",
  683.                        escstr);
  684.                 printf("%s?\t-- This help message.\n", escstr);
  685.                 printf("%s~\t-- Send a single meta character.\n",
  686.                        escstr);
  687.                 printf("%s.\t-- Disconnect advise session.\n",
  688.                        escstr);
  689.                 printf("%s=C\t-- Change meta character to C.\n",
  690.                        escstr);
  691.                 printf("%s^Z\t-- Suspend advise session.\n",
  692.                        escstr);
  693.                 pp++;
  694.                 metad=0;
  695.                 break;
  696.                 }
  697.  
  698.                 case '.':
  699.                 {
  700.                 if (!secret)
  701.                 {
  702.                     char *str;
  703.  
  704.                     str = malloc(strlen(login_name) +
  705.                       strlen(tty_name) +
  706.                       sizeof("[: disconnecting from :]\n") +
  707.                            strlen(username) + strlen(devname));
  708.  
  709.                     if (str)
  710.                     {
  711.                     struct advise_message m;
  712.                     struct strbuf ctl, data;
  713.  
  714.                     m.type = ADVISE_READDATA;
  715.  
  716.                     ctl.len = sizeof(m);
  717.                     ctl.buf = (void *)&m;
  718.  
  719.                     sprintf(str, "[%s:%s disconnecting from %s:%s]\n\r",
  720.                         login_name, tty_name, username,
  721.                         devname);
  722.  
  723.                     data.len = strlen(str);
  724.                     data.buf = str;
  725.  
  726.                     (void) putmsg(fd, &ctl, &data, 0);
  727.  
  728.                     free(str);
  729.                     }
  730.                 }
  731.  
  732.                 close(fd);
  733.  
  734.                 (void) ioctl(0, TCSETS, &oldtermios);
  735.  
  736.                 exit(0);
  737.                 }
  738.  
  739.                 case CTRL('Z'):
  740.                 {
  741.                 (void) ioctl(0, TCSETS, &oldtermios);
  742.                 (void) signal(SIGTSTP, SIG_DFL);
  743.                 (void) kill(0, SIGTSTP);
  744.                 (void) ioctl(0, TCSETS, &termios);
  745.                 pp++;
  746.                 metad=0;
  747.                 break;
  748.                 }
  749.  
  750.                 default:
  751.                 metad=0;
  752.                 break;
  753.                 }
  754.             }
  755.             else
  756.             {
  757.                 if (*p == meta_character)
  758.                 {
  759.                 int d = p - pp;
  760.  
  761.                 metad=1;
  762.  
  763.                 if (d) write(fd, pp, d);
  764.  
  765.                 pp += d + 1;
  766.                 i += d;
  767.                 }
  768.             }
  769.             }
  770.  
  771.             if (p - pp) write(fd, pp, p-pp);
  772.         }
  773.     }
  774.     }
  775. }
  776.  
  777. static struct module_list *
  778. #ifdef __STDC__
  779. list_modules(int fd, char *push_below)
  780. #else
  781. list_modules(fd, push_below)
  782. char *push_below;
  783. #endif /* __STDC__ */
  784. {
  785.     char lookbuf[max(FMNAMESZ+1,256)];
  786.     struct module_list *mp, *mpp;
  787.  
  788.     mp = NULL;
  789.  
  790.     while (ioctl(fd, I_LOOK, lookbuf) == 0)
  791.     {
  792.     if (ioctl(fd, I_POP, 0))
  793.     {
  794.         (void) fprintf(stderr, "%s: Couldn't I_POP: %s (%s).\n", progname,
  795.                lookbuf, strerror(errno));
  796.         return mp;
  797.     }
  798.  
  799.     if ((mpp = (struct module_list *)malloc(sizeof(struct module_list)))
  800.         == NULL || (mpp->name = malloc(strlen(lookbuf) + 1)) == NULL)
  801.     {
  802.         (void) fprintf(stderr, "%s: Couldn't malloc (out of memory).\n",
  803.                progname);
  804.         return mp;
  805.     }
  806.  
  807.     mpp->next = mp;
  808.     mp = mpp;
  809.  
  810.     strcpy(mp->name, lookbuf);
  811.  
  812.     if (!strcmp(push_below, lookbuf))
  813.         break;
  814.     }
  815.  
  816.     return mp;
  817. }
  818.  
  819. static char *
  820. #ifdef __STDC__
  821. strchar(char character)
  822. #else
  823. strchar(character)
  824. char character;
  825. #endif /* __STDC__ */
  826. {
  827.     static char retbuf[4];
  828.     char *p = retbuf;
  829.     int capit = 0;
  830.  
  831.     if (!isascii(character))
  832.     {
  833.     *p++ = '~';
  834.     capit = 1;
  835.     character = toascii(character);
  836.     }
  837.  
  838.     if (iscntrl(character))
  839.     {
  840.     *p++ = '^';
  841.     capit = 1;
  842.     character += '@';
  843.     }
  844.  
  845.     if (capit)
  846.     *p++ = toupper(character);
  847.     else
  848.     *p++ = character;
  849.  
  850.     *p = '\0';
  851.  
  852.     return retbuf;
  853. }
  854.