home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnusrvr2.zip / gnuserv.c < prev    next >
C/C++ Source or Header  |  1997-05-15  |  22KB  |  866 lines

  1. /* -*-C-*-
  2.  Server code for handling requests from clients and forwarding them
  3.  on to the GNU Emacs process.
  4.  
  5.  This file is part of GNU Emacs.
  6.  
  7.  Copying is permitted under those conditions described by the GNU
  8.  General Public License.
  9.  
  10.  Copyright (C) 1989 Free Software Foundation, Inc.
  11.  
  12.  Author: Andy Norman (ange@hplb.hpl.hp.com), based on 'etc/server.c'
  13.          from the 18.52 GNU Emacs distribution.
  14.  
  15.  Please mail bugs and suggestions to the author at the above address.
  16. */
  17.  
  18. /* HISTORY 
  19.  * 11-Nov-1990        bristor@simba    
  20.  *    Added EOT stuff.
  21.  */
  22.  
  23. /*
  24.  * This file incorporates new features added by Bob Weiner <weiner@mot.com>,
  25.  * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>.
  26.  * Please see the note at the end of the README file for details.
  27.  *
  28.  * (If gnuserv came bundled with your emacs, the README file is probably
  29.  * ../etc/gnuserv.README relative to the directory containing this file)
  30.  */
  31.  
  32. static char rcsid [] = "$Header: gnuserv.c,v 2.1 95/02/16 11:58:27 arup alpha $";
  33.  
  34. #include "gnuserv.h"
  35.  
  36. #if defined( OS2_EMX )
  37. #define INCL_WINSWITCHlIST
  38. #include <os2.h>
  39. #endif
  40.  
  41.  
  42. #ifdef USE_LITOUT
  43. #ifdef linux
  44. #include <bsd/sgtty.h>
  45. #else
  46. #include <sgtty.h>
  47. #endif
  48. #endif
  49.  
  50. #ifdef AIX
  51. #include <sys/select.h>
  52. #endif
  53.  
  54. #if !defined(SYSV_IPC) && !defined(UNIX_DOMAIN_SOCKETS) && \
  55.     !defined(INTERNET_DOMAIN_SOCKETS)
  56. main ()
  57. {
  58.   fprintf (stderr,"Sorry, the Emacs server is only supported on systems that have\n");
  59.   fprintf (stderr,"Unix Domain sockets, Internet Domain sockets or System V IPC\n");
  60.   exit (1);
  61. } /* main */
  62. #else /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */
  63.  
  64. #ifdef SYSV_IPC
  65.  
  66. int ipc_qid = 0;        /* ipc message queue id */
  67. int ipc_wpid = 0;        /* watchdog task pid */
  68.  
  69.  
  70. /*
  71.   ipc_exit -- clean up the queue id and queue, then kill the watchdog task
  72.               if it exists. exit with the given status.
  73. */
  74. void ipc_exit(stat)
  75.      int stat;
  76. {
  77.   msgctl(ipc_qid,IPC_RMID,0);
  78.   
  79.   if (ipc_wpid != 0)
  80.     kill(ipc_wpid,SIGKILL);
  81.  
  82.   exit(stat);
  83. } /* ipc_exit */
  84.  
  85.  
  86. /*
  87.   ipc_handle_signal -- catch the signal given and clean up.
  88. */
  89. void ipc_handle_signal(sig)
  90.      int sig;
  91. {
  92.   ipc_exit(0);
  93. } /* ipc_handle_signal */
  94.  
  95.  
  96. /* 
  97.   ipc_spawn_watchdog -- spawn a watchdog task to clean up the message queue should the
  98.             server process die.
  99. */
  100. void ipc_spawn_watchdog()
  101. {
  102.   if ((ipc_wpid = fork()) == 0) { /* child process */
  103.     int ppid = getppid();    /* parent's process id */
  104.  
  105.     setpgrp();            /* gnu kills process group on exit */
  106.     
  107.     while (1) {
  108.       if (kill(ppid,0) < 0) {    /* ppid is no longer valid, parent may have died */
  109.     ipc_exit(0);
  110.       }; /* if */
  111.  
  112.       sleep(10);        /* have another go later */
  113.     }; /* while */
  114.   }; /* if */
  115.  
  116. } /* ipc_spawn_watchdog */
  117.  
  118.  
  119. /*
  120.   ipc_init -- initialize server, setting the global msqid that can be listened on.
  121. */
  122. void ipc_init(msgpp)
  123.      struct msgbuf **msgpp;
  124. {
  125.   key_t key;            /* messge key */
  126.   char buf[GSERV_BUFSZ];    /* pathname for key */
  127.  
  128.   sprintf(buf,"/tmp/gsrv%d",(int)geteuid());
  129.   creat(buf,0600);
  130.   key = ftok(buf,1);
  131.  
  132.   if ((ipc_qid = msgget(key,0600|IPC_CREAT)) == -1) {
  133.     perror(progname);
  134.     fprintf(stderr,"%s: unable to create msg queue\n",progname);
  135.     ipc_exit(1);
  136.   }; /* if */
  137.  
  138.   ipc_spawn_watchdog();
  139.  
  140.   signal(SIGTERM,ipc_handle_signal);
  141.   signal(SIGINT,ipc_handle_signal);
  142.  
  143.   if ((*msgpp = (struct msgbuf *) 
  144.                 malloc(sizeof **msgpp + GSERV_BUFSZ)) == NULL) {
  145.     fprintf(stderr,
  146.         "%s: unable to allocate space for message buffer\n",progname);
  147.     ipc_exit(1);
  148.   }; /* if */
  149.  
  150. } /* ipc_init */
  151.  
  152.  
  153. /*
  154.   handle_ipc_request -- accept a request from a client, pass the request on
  155.               to the GNU Emacs process, then wait for its reply and
  156.             pass that on to the client.
  157. */
  158. void handle_ipc_request(msgp)
  159.      struct msgbuf *msgp;    /* message buffer */
  160. {
  161.   struct msqid_ds msg_st;    /* message status */
  162.   char buf[GSERV_BUFSZ];
  163.   int len;            /* length of message / read */
  164.   int s, result_len;            /* tag fields on the response from emacs */
  165.   int offset = 0;
  166.   int total = 1;                /* # bytes that will actually be sent off */
  167.  
  168.   if ((len = msgrcv(ipc_qid,msgp,GSERV_BUFSZ-1,1,0)) < 0) {
  169.     perror(progname);
  170.     fprintf(stderr,"%s: unable to receive\n",progname);
  171.     ipc_exit(1);
  172.   }; /* if */
  173.  
  174.   msgctl(ipc_qid,IPC_STAT,&msg_st);
  175.   strncpy(buf,msgp->mtext,len);
  176.   buf[len] = '\0';        /* terminate */
  177.   
  178.   printf("%d %s",ipc_qid,buf);
  179.   fflush(stdout);
  180.  
  181.   /* now for the response from gnu */
  182.   msgp->mtext[0] = '\0';
  183.  
  184. #if 0
  185.   if ((len = read(0,buf,GSERV_BUFSZ)) < 0) {
  186.     perror(progname);
  187.     fprintf(stderr,"%s: unable to read\n",progname);
  188.     ipc_exit(1);
  189.   }; /* if */
  190.       
  191.   sscanf(buf,"%d:%[^\n]\n",&junk,msgp->mtext);
  192. #else 
  193.  
  194.   /* read in "n/m:" (n=client fd, m=message length) */
  195.  
  196.   while (offset < GSERV_BUFSZ && 
  197.      ((len = read(0,buf+offset,1)) > 0) &&
  198.      buf[offset] != ':') {
  199.     offset += len;
  200.   }
  201.  
  202.   if (len < 0) {
  203.     perror(progname);
  204.     fprintf(stderr,"%s: unable to read\n",progname);
  205.     exit(1);
  206.   }
  207.       
  208.   /* parse the response from emacs, getting client fd & result length */
  209.   buf[offset] = '\0';
  210.   sscanf(buf,"%d/%d", &s, &result_len);
  211.  
  212.   while (result_len > 0) {
  213.     if ((len = read(0,buf,min2(result_len, GSERV_BUFSZ - 1))) < 0) {
  214.       perror(progname);
  215.       fprintf(stderr,"%s: unable to read\n",progname);
  216.       exit(1);
  217.     }
  218.  
  219.     /* Send this string off, but only if we have enough space */ 
  220.  
  221.     if (GSERV_BUFSZ > total) {
  222.       if (total + len <= GSERV_BUFSZ)
  223.     buf[len] = 0;
  224.       else 
  225.     buf[GSERV_BUFSZ - total] = 0;
  226.  
  227.       send_string(s,buf);
  228.       total += strlen(buf);
  229.     };
  230.  
  231.     result_len -= len;
  232.   }
  233.  
  234.   /* eat the newline */
  235.   while ((len = read(0,buf,1)) == 0)
  236.     ;
  237.   if (len < 0) {
  238.     perror(progname);
  239.     fprintf(stderr,"%s: unable to read\n",progname);
  240.     exit(1);
  241.   }
  242.   if (buf[0] != '\n') {
  243.     fprintf(stderr,"%s: garbage after result [%c]\n",progname, buf[0]);
  244.     exit(1);
  245.   }
  246. #endif
  247.  
  248.   /* Send a response back to the client. */
  249.  
  250.   msgp->mtype = msg_st.msg_lspid;
  251.   if (msgsnd(ipc_qid,msgp,strlen(msgp->mtext)+1,0) < 0)
  252.     perror("msgsend(gnuserv)");
  253.  
  254. } /* handle_ipc_request */
  255. #endif /* SYSV_IPC */
  256.  
  257.  
  258. #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
  259. /*
  260.   echo_request -- read request from a given socket descriptor, and send the information
  261.                   to stdout (the gnu process).
  262. */
  263. void echo_request(s)
  264. int s;                /* socket */
  265. {
  266.   char buf[GSERV_BUFSZ];
  267.   int len;
  268.  
  269.   printf("%d ",s);
  270.   
  271.   /* read until we get a newline or no characters */
  272.   while ((len = recv(s,buf,GSERV_BUFSZ,0)) > 0) {
  273.     buf[len] = '\0';
  274.     printf("%s",buf);
  275.  
  276.     if (buf[len-1] == EOT_CHR) {
  277.       fflush(stdout);
  278.       break;            /* end of message */
  279.     }
  280.  
  281.   }; /* while */
  282.  
  283.   if (len < 0) {
  284.     perror(progname);
  285.     fprintf(stderr,"%s: unable to recv\n",progname);
  286.     exit(1);
  287.   }; /* if */
  288.   
  289. } /* echo_request */
  290.  
  291.  
  292. /*
  293.   handle_response -- accept a response from stdin (the gnu process) and pass the
  294.                      information on to the relevant client.
  295. */
  296. void handle_response()
  297. {
  298.   char buf[GSERV_BUFSZ+1];
  299.   int offset=0;
  300.   int s;
  301.   int len;
  302.   int result_len;
  303.  
  304.   /* read in "n/m:" (n=client fd, m=message length) */
  305.   while (offset < GSERV_BUFSZ && 
  306.      ((len = read(0,buf+offset,1)) > 0) &&
  307.      buf[offset] != ':') {
  308.     offset += len;
  309.   }
  310.  
  311.   if (len < 0) {
  312.     perror(progname);
  313.     fprintf(stderr,"%s: unable to read\n",progname);
  314.     exit(1);
  315.   }
  316.       
  317.   /* parse the response from emacs, getting client fd & result length */
  318.   buf[offset] = '\0';
  319.   sscanf(buf,"%d/%d", &s, &result_len);
  320.  
  321.   while (result_len > 0) {
  322.     if ((len = read(0,buf,min2(result_len,GSERV_BUFSZ))) < 0) {
  323.       perror(progname);
  324.       fprintf(stderr,"%s: unable to read\n",progname);
  325.       exit(1);
  326.     }
  327.     buf[len] = '\0';
  328.     send_string(s,buf);
  329.     result_len -= len;
  330.   }
  331.  
  332.   /* eat the newline */
  333.   while ((len = read(0,buf,1)) == 0)
  334.     ;
  335.   if (len < 0) {
  336.     perror(progname);
  337.     fprintf(stderr,"%s: unable to read\n",progname);
  338.     exit(1);
  339.   }
  340.   if (buf[0] != '\n') {
  341.     fprintf(stderr,"%s: garbage after result\n",progname);
  342.     exit(1);
  343.   }
  344.   close(s);
  345.  
  346. } /* handle_response */
  347. #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
  348.  
  349.  
  350. #ifdef INTERNET_DOMAIN_SOCKETS
  351. struct entry {
  352.   u_long host_addr;
  353.   struct entry *next;
  354. };
  355.  
  356. struct entry *permitted_hosts[TABLE_SIZE];
  357.  
  358. #ifdef AUTH_MAGIC_COOKIE
  359. # include <X11/X.h>
  360. # include <X11/Xauth.h>
  361.  
  362. static Xauth *server_xauth = NULL;
  363. #endif 
  364.  
  365. int 
  366. timed_read (fd, buf, max, timeout, one_line)
  367. int fd, max, timeout, one_line;
  368. char *buf;
  369. {
  370.   fd_set rmask;
  371.   struct timeval tv; /* = {timeout, 0}; */
  372.   char c = 0;
  373.   int nbytes = 0;
  374.   int r;
  375.   
  376.   tv.tv_sec = timeout;
  377.   tv.tv_usec = 0;
  378.  
  379.   FD_ZERO(&rmask);
  380.   FD_SET(fd, &rmask);
  381.   
  382.   do {
  383.     r = select(fd + 1, &rmask, NULL, NULL, &tv);
  384.  
  385.     if (r > 0) {
  386.       if (read (fd, &c, 1) == 1 ){
  387.     *buf++ = c;
  388.     ++nbytes;
  389.       } else {
  390.     printf ("read error on socket\004\n");
  391.     return -1;
  392.       }
  393.     } else if (r == 0) {
  394.       return -1;
  395.     } else {
  396.       return -1;
  397.     }
  398.   } while ((nbytes < max) &&  !(one_line && (c == '\n')));
  399.  
  400.   --buf;
  401.   if (one_line && *buf == '\n') {
  402.     *buf = 0;
  403.   }
  404.  
  405.   return nbytes;
  406. }
  407.     
  408.     
  409.  
  410. /*
  411.   permitted -- return whether a given host is allowed to connect to the server.
  412. */
  413. int permitted(host_addr, fd)
  414.      u_long host_addr;
  415.      int fd;
  416. {
  417.   int key;
  418.   struct entry *entry;
  419.  
  420.   char auth_protocol[128]; 
  421.   char buf[1024];
  422.   int  auth_data_len;
  423.  
  424.   if (fd > 0) {
  425.     /* we are checking permission on a real connection */
  426.  
  427.     /* Read auth protocol name */
  428.   
  429.     if (timed_read(fd, auth_protocol, AUTH_NAMESZ, AUTH_TIMEOUT, 1) <= 0)
  430.       return FALSE;
  431.  
  432.     if (strcmp (auth_protocol, DEFAUTH_NAME) &&
  433.     strcmp (auth_protocol, MCOOKIE_NAME)) {
  434.       printf ("authentication protocol (%s) from client is invalid...\n", 
  435.           auth_protocol);
  436.       printf ("... Was the client an old version of gnuclient/gnudoit?\004\n");
  437.       
  438.       return FALSE;
  439.     }
  440.  
  441.     if (!strcmp(auth_protocol, MCOOKIE_NAME)) {
  442.  
  443.       /*
  444.        * doing magic cookie auth
  445.        */
  446.  
  447.       if (timed_read(fd, buf, 10, AUTH_TIMEOUT, 1) <= 0)
  448.     return FALSE;
  449.  
  450.       auth_data_len = atoi(buf);
  451.  
  452.       if (timed_read(fd, buf, auth_data_len, AUTH_TIMEOUT, 0) != auth_data_len)
  453.     return FALSE;
  454.       
  455. #ifdef AUTH_MAGIC_COOKIE
  456.       if (server_xauth && server_xauth->data &&
  457.       !bcmp(buf, server_xauth->data, auth_data_len)) {
  458.     return TRUE;
  459.       }
  460. #else 
  461.       printf ("client tried Xauth, but server is not compiled with Xauth\n");
  462. #endif
  463.       
  464.       /*
  465.        * auth failed, but allow this to fall through to the GNU_SECURE
  466.        * protocol....
  467.        */
  468.  
  469.       printf ("Xauth authentication failed, trying GNU_SECURE auth...\004\n");
  470.  
  471.     }
  472.     
  473.     /* Other auth protocols go here, and should execute only if the
  474.      * auth_protocol name matches.
  475.      */
  476.  
  477.   }
  478.  
  479.  
  480.   /* Now, try the old GNU_SECURE stuff... */
  481.   
  482.   /* First find the hash key */
  483.   key = HASH(host_addr) % TABLE_SIZE;
  484.   
  485.   /* Now check the chain for that hash key */
  486.   for(entry=permitted_hosts[key]; entry != NULL; entry=entry->next)
  487.     if (host_addr == entry->host_addr) 
  488.       return(TRUE);
  489.   
  490.   return(FALSE);
  491.  
  492. } /* permitted */
  493.  
  494.  
  495. /* 
  496.   add_host -- add the given host to the list of permitted hosts, provided it isn't
  497.               already there.
  498. */    
  499. void add_host(host_addr)
  500.      u_long host_addr;
  501. {
  502.   int key;
  503.   struct entry *new_entry;
  504.   
  505.   if (!permitted(host_addr, -1)) {
  506.     if ((new_entry = (struct entry *) malloc(sizeof(struct entry))) == NULL) {
  507.       fprintf(stderr,"%s: unable to malloc space for permitted host entry\n",
  508.           progname);
  509.       exit(1);
  510.     }; /* if */
  511.  
  512.     new_entry->host_addr = host_addr;
  513.     key = HASH(host_addr) % TABLE_SIZE;
  514.     new_entry->next = permitted_hosts[key];
  515.     permitted_hosts[key] = new_entry;
  516.   }; /* if */
  517.  
  518. } /* add_host */
  519.  
  520.  
  521. /*
  522.   setup_table -- initialise the table of hosts allowed to contact the server,
  523.                  by reading from the file specified by the GNU_SECURE
  524.          environment variable
  525.                  Put in the local machine, and, if a security file is specifed,
  526.                  add each host that is named in the file.
  527.          Return the number of hosts added.
  528. */
  529. int setup_table()
  530. {
  531.   FILE *host_file;
  532.   char *file_name;
  533.   char hostname[HOSTNAMSZ];
  534.   u_int host_addr;
  535.   int i, hosts=0;
  536.   
  537.   /* Make sure every entry is null */
  538.   for (i=0; i<TABLE_SIZE; i++)
  539.     permitted_hosts[i] = NULL;
  540.  
  541.   gethostname(hostname,HOSTNAMSZ);
  542.  
  543.   if ((host_addr = internet_addr(hostname)) == -1) {
  544.     fprintf(stderr,"%s: unable to find %s in /etc/hosts or from YP", 
  545.         progname,hostname);
  546.     exit(1);
  547.   }; /* if */
  548.  
  549. #ifdef AUTH_MAGIC_COOKIE
  550.   
  551.   server_xauth = XauGetAuthByAddr (FamilyInternet, 
  552.                    sizeof(host_addr), (char *)&host_addr,
  553.                    strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN, 
  554.                    strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME);
  555.   hosts++;
  556.  
  557. #endif /* AUTH_MAGIC_COOKIE */
  558.   
  559.  
  560. #if 0 /* Don't even want to allow access from the local host by default */
  561.   add_host(host_addr);                    /* add local host */
  562. #endif 
  563.  
  564. #if !defined( OS2_EMX )
  565.   
  566.   if (((file_name = getenv("GNU_SECURE")) != NULL &&    /* security file  */
  567.        (host_file = fopen(file_name,"r")) != NULL)) {    /* opened ok */
  568.     while ((fscanf(host_file,"%s",hostname) != EOF))    /* find a host */
  569.       if ((host_addr = internet_addr(hostname)) != -1) {/* get its addr */
  570.     add_host(host_addr);                /* add the addr */
  571.         hosts++;
  572.       }
  573.     fclose(host_file);
  574.   }; /* if */
  575.  
  576. #else /* OS2_EMX Defined */
  577.  
  578.   host_addr = internet_addr( "localhost" );
  579.  
  580.   if( host_addr == -1 )
  581.   {
  582.       fprintf( stderr, "Unable to get address for localhost.\n" );
  583.       fflush( stderr );
  584.       exit( 1 );
  585.   }
  586.   else
  587.   {
  588.       add_host( internet_addr( "localhost" ) );
  589.       hosts++;
  590.   }
  591.  
  592. #endif /* ! OS2_EMX */
  593.       
  594.   return hosts;
  595. } /* setup_table */
  596.  
  597.  
  598. /*
  599.   internet_init -- initialize server, returning an internet socket that can
  600.                     be listened on.
  601. */
  602. int internet_init()
  603. {
  604.   int ls;            /* socket descriptor */
  605.   struct servent *sp;        /* pointer to service information */
  606.   struct sockaddr_in server;    /* for local socket address */
  607.   char *ptr;            /* ptr to return from getenv */
  608.  
  609.   if (setup_table() == 0) 
  610.     return -1;
  611.  
  612.   
  613.   /* clear out address structure */
  614.   bzero((char *)&server,sizeof(struct sockaddr_in));
  615.   
  616.   /* Set up address structure for the listen socket. */
  617.   server.sin_family = AF_INET;
  618.   server.sin_addr.s_addr = INADDR_ANY;
  619.  
  620.   /* Find the information for the gnu server
  621.    * in order to get the needed port number.
  622.    */
  623.   if ((ptr=getenv("GNU_PORT")) != NULL)
  624.   {
  625.       server.sin_port = htons(atoi(ptr));
  626.   }
  627.   else if ((sp = getservbyname ("gnuserv", "tcp")) == NULL)
  628.   {
  629.       server.sin_port = htons(DEFAULT_PORT+getuid());
  630.   }
  631.   else
  632.   {
  633.       server.sin_port = sp->s_port;
  634.   }
  635.  
  636.   fflush( stdout );
  637.   
  638.   
  639.   /* Create the listen socket. */
  640.   if ((ls = socket (AF_INET,SOCK_STREAM, 0)) == -1) {
  641.     perror(progname);
  642.     fprintf(stderr,"%s: unable to create socket\n",progname);
  643.     exit(1);
  644.   }; /* if */
  645.   
  646.   /* Bind the listen address to the socket. */
  647.   if (bind(ls,(struct sockaddr *) &server,sizeof(struct sockaddr_in)) == -1) {
  648.     perror(progname);
  649.     fprintf(stderr,"%s: unable to bind socket\n",progname);
  650.     exit(1);
  651.   }; /* if */
  652.  
  653.   /* Initiate the listen on the socket so remote users
  654.    * can connect. 
  655.    */
  656.   if (listen(ls,20) == -1) {
  657.     perror(progname);
  658.     fprintf(stderr,"%s: unable to listen\n",progname);
  659.     exit(1);
  660.   }; /* if */
  661.  
  662.   return(ls);
  663.  
  664. } /* internet_init */
  665.  
  666.  
  667. /*
  668.   handle_internet_request -- accept a request from a client and send the information
  669.                              to stdout (the gnu process).
  670. */
  671. void handle_internet_request(ls)
  672. int ls;                /* listen socket */
  673. {
  674.   int s;
  675.   int addrlen = sizeof(struct sockaddr_in);
  676.   struct sockaddr_in peer;    /* for peer socket address */
  677.  
  678.   bzero((char *)&peer,sizeof(struct sockaddr_in));
  679.  
  680.   if ((s = accept(ls,(struct sockaddr *)&peer,&addrlen)) == -1) {
  681.     perror(progname);
  682.     fprintf(stderr,"%s: unable to accept\n",progname);
  683.     exit(1);
  684.   }; /* if */
  685.     
  686.   /* Check that access is allowed - if not return crud to the client */
  687.   if (!permitted(peer.sin_addr.s_addr, s)) {
  688.     send_string(s,"gnudoit: Connection refused\ngnudoit: unable to connect to remote");
  689.     close(s);
  690.  
  691.     printf("Refused connection from %s\004\n", inet_ntoa(peer.sin_addr));
  692.     return;
  693.   }; /* if */
  694.  
  695.   echo_request(s);
  696.   
  697. } /* handle_internet_request */
  698. #endif /* INTERNET_DOMAIN_SOCKETS */
  699.  
  700.  
  701. #ifdef UNIX_DOMAIN_SOCKETS
  702. /*
  703.   unix_init -- initialize server, returning an unix-domain socket that can
  704.                be listened on.
  705. */
  706. int unix_init()
  707. {
  708.   int ls;            /* socket descriptor */
  709.   struct sockaddr_un server;     /* unix socket address */
  710.  
  711.   if ((ls = socket(AF_UNIX,SOCK_STREAM, 0)) < 0) {
  712.     perror(progname);
  713.     fprintf(stderr,"%s: unable to create socket\n",progname);
  714.     exit(1);
  715.   }; /* if */
  716.  
  717.   /* Set up address structure for the listen socket. */
  718. #ifdef HIDE_UNIX_SOCKET
  719.   sprintf(server.sun_path,"/tmp/gsrvdir%d",(int)geteuid());
  720.   if (mkdir(server.sun_path, 0700) < 0) {
  721.     /* assume it already exists, and try to set perms */
  722.     if (chmod(server.sun_path, 0700) < 0) {
  723.       perror(progname);
  724.       fprintf(stderr,"%s: can't set permissions on %s\n",
  725.           progname, server.sun_path);
  726.       exit(1);
  727.     }
  728.   }
  729.   strcat(server.sun_path,"/gsrv");
  730.   unlink(server.sun_path);    /* remove old file if it exists */
  731. #else /* HIDE_UNIX_SOCKET */
  732.   sprintf(server.sun_path,"/tmp/gsrv%d",(int)geteuid());
  733.   unlink(server.sun_path);    /* remove old file if it exists */
  734. #endif /* HIDE_UNIX_SOCKET */
  735.  
  736.   server.sun_family = AF_UNIX;
  737.  
  738.   if (bind(ls,(struct sockaddr *)&server,strlen(server.sun_path)+2) < 0) {
  739.     perror(progname);
  740.     fprintf(stderr,"%s: unable to bind socket\n",progname);
  741.     exit(1);
  742.   }; /* if */
  743.  
  744.   chmod(server.sun_path,0700);    /* only this user can send commands */
  745.  
  746.   if (listen(ls,20) < 0) {
  747.     perror(progname);
  748.     fprintf(stderr,"%s: unable to listen\n",progname);
  749.     exit(1);
  750.   }; /* if */
  751.  
  752.   signal(SIGPIPE,SIG_IGN);    /* in case user kills client */
  753.  
  754.   return(ls);
  755.  
  756. } /* unix_init */
  757.  
  758.  
  759. /*
  760.   handle_unix_request -- accept a request from a client and send the information
  761.                          to stdout (the gnu process).
  762. */
  763. void handle_unix_request(ls)
  764. int ls;                /* listen socket */
  765. {
  766.   int s;
  767.   int len = sizeof(struct sockaddr_un);
  768.   struct sockaddr_un server;     /* for unix socket address */
  769.  
  770.   server.sun_family = AF_UNIX;
  771.  
  772.   if ((s = accept(ls,(struct sockaddr *)&server,&len)) < 0) {
  773.     perror(progname);
  774.     fprintf(stderr,"%s: unable to accept\n",progname);
  775.   }; /* if */
  776.  
  777.   echo_request(s);
  778.   
  779. } /* handle_unix_request */
  780. #endif /* UNIX_DOMAIN_SOCKETS */
  781.  
  782.  
  783. void
  784. main(argc,argv)
  785.      int argc;
  786.      char *argv[];
  787. {
  788.   int chan;            /* temporary channel number */
  789. #ifdef SYSV_IPC
  790.   struct msgbuf *msgp;        /* message buffer */
  791. #else 
  792.   int ils = -1;                 /* internet domain listen socket */
  793.   int uls = -1;                 /* unix domain listen socket */
  794. #endif /* SYSV_IPC */
  795.  
  796.  
  797. #if defined( OS2_EMX )
  798.   unsigned long switch_list;
  799.   switch_list = WinQuerySwitchHandle( NULLHANDLE, getpid() );
  800.   WinRemoveSwitchEntry( switch_list );
  801. #endif
  802.  
  803.  
  804.   progname = argv[0];
  805.  
  806.   for(chan=3; chan < _NFILE; close(chan++)) /* close unwanted channels */
  807.     ;
  808.  
  809. #ifdef USE_LITOUT
  810.   {
  811.     /* this is to allow ^D to pass to emacs */
  812.     int d = LLITOUT;
  813.     (void) ioctl(fileno(stdout), TIOCLBIS, &d);
  814.   }
  815. #endif
  816.  
  817. #ifdef SYSV_IPC
  818.   ipc_init(&msgp);        /* get a msqid to listen on, and a message buffer */
  819. #endif /* SYSV_IPC */
  820.  
  821. #ifdef INTERNET_DOMAIN_SOCKETS
  822.   ils = internet_init();    /* get a internet domain socket to listen on */
  823. #endif /* INTERNET_DOMAIN_SOCKETS */
  824.  
  825. #ifdef UNIX_DOMAIN_SOCKETS
  826.   uls = unix_init();        /* get a unix domain socket to listen on */
  827. #endif /* UNIX_DOMAIN_SOCKETS */
  828.  
  829.   while (1) {
  830. #ifdef SYSV_IPC
  831.     handle_ipc_request(msgp);
  832. #else /* NOT SYSV_IPC */
  833.     fd_set rmask;
  834.     FD_ZERO(&rmask);
  835.     FD_SET(fileno(stdin), &rmask);
  836.     if (uls >= 0)
  837.       FD_SET(uls, &rmask);
  838.     if (ils >= 0)
  839.       FD_SET(ils, &rmask);
  840.     
  841.     if (select(max2(fileno(stdin),max2(uls,ils)) + 1, &rmask, 
  842.            (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL) < 0) {
  843.       perror(progname);
  844.       fprintf(stderr,"%s: unable to select\n",progname);
  845.       exit(1);
  846.     }; /* if */
  847.  
  848. #ifdef UNIX_DOMAIN_SOCKETS
  849.     if (uls > 0 && FD_ISSET(uls, &rmask))
  850.       handle_unix_request(uls);
  851. #endif
  852.  
  853. #ifdef INTERNET_DOMAIN_SOCKETS
  854.     if (ils > 0 && FD_ISSET(ils, &rmask))
  855.       handle_internet_request(ils);
  856. #endif /* INTERNET_DOMAIN_SOCKETS */
  857.  
  858.     if (FD_ISSET(fileno(stdin), &rmask))      /* from stdin (gnu process) */
  859.       handle_response();
  860. #endif /* NOT SYSV_IPC */
  861.   }; /* while */
  862.  
  863. } /* main */
  864.  
  865. #endif /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */
  866.