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