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 34char 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) 64main () 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 74int ipc_qid = 0; /* ipc message queue id */ 75pid_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*/ 82void 83ipc_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*/ 97void 98ipc_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*/ 108void 109ipc_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*/ 135void 136ipc_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*/ 172void 173handle_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*/ 286static void 287echo_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*/ 319static void 320handle_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 380struct entry { 381 u_long host_addr; 382 struct entry *next; 383}; 384 385struct entry *permitted_hosts[TABLE_SIZE]; 386 387#ifdef AUTH_MAGIC_COOKIE 388# include <X11/X.h> 389# include <X11/Xauth.h> 390 391static Xauth *server_xauth = NULL; 392#endif 393 394static int 395timed_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*/ 452static int 453permitted (u_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 int auth_data_pos; 462 int auth_mismatches; 463 464 if (fd > 0) 465 { 466 /* we are checking permission on a real connection */ 467 468 /* Read auth protocol name */ 469 470 if (timed_read(fd, auth_protocol, AUTH_NAMESZ, AUTH_TIMEOUT, 1) <= 0) 471 return FALSE; 472 473 if (strcmp (auth_protocol, DEFAUTH_NAME) && 474 strcmp (auth_protocol, MCOOKIE_NAME)) 475 { 476 printf ("authentication protocol (%s) from client is invalid...\n", 477 auth_protocol); 478 printf ("... Was the client an old version of gnuclient/gnudoit?\004\n"); 479 480 return FALSE; 481 } 482 483 if (!strcmp(auth_protocol, MCOOKIE_NAME)) 484 { 485 486 /* 487 * doing magic cookie auth 488 */ 489 490 if (timed_read(fd, buf, 10, AUTH_TIMEOUT, 1) <= 0) 491 return FALSE; 492 493 auth_data_len = atoi(buf); 494 495 if (auth_data_len <= 0 || auth_data_len > sizeof(buf)) 496 { 497 return FALSE; 498 } 499 500 if (timed_read(fd, buf, auth_data_len, AUTH_TIMEOUT, 0) != auth_data_len) 501 return FALSE; 502 503#ifdef AUTH_MAGIC_COOKIE 504 if (server_xauth && server_xauth->data) 505 { 506 /* Do a compare without comprising info about 507 the size of the cookie */ 508 auth_mismatches = 509 ( auth_data_len ^ 510 server_xauth->data_length ); 511 512 for(auth_data_pos=0; auth_data_pos < auth_data_len; ++auth_data_pos) 513 auth_mismatches |= 514 ( buf[auth_data_pos] ^ 515 server_xauth->data[auth_data_pos % server_xauth->data_length]); 516 517 if (auth_mismatches == 0) 518 return TRUE; 519 520 for(;rand() % 1000;); 521 } 522 523#else 524 printf ("client tried Xauth, but server is not compiled with Xauth\n"); 525#endif 526 527 /* 528 * auth failed, but allow this to fall through to the GNU_SECURE 529 * protocol.... 530 */ 531 532 printf ("Xauth authentication failed, trying GNU_SECURE auth...\004\n"); 533 534 } 535 536 /* Other auth protocols go here, and should execute only if the 537 * auth_protocol name matches. 538 */ 539 540 } 541 542 543 /* Now, try the old GNU_SECURE stuff... */ 544 545 /* First find the hash key */ 546 key = HASH(host_addr) % TABLE_SIZE; 547 548 /* Now check the chain for that hash key */ 549 for(entry=permitted_hosts[key]; entry != NULL; entry=entry->next) 550 if (host_addr == entry->host_addr) 551 return(TRUE); 552 553 return(FALSE); 554 555} /* permitted */ 556 557 558/* 559 add_host -- add the given host to the list of permitted hosts, provided it isn't 560 already there. 561*/ 562static void 563add_host (u_long host_addr) 564{ 565 int key; 566 struct entry *new_entry; 567 568 if (!permitted(host_addr, -1)) 569 { 570 if ((new_entry = (struct entry *) malloc(sizeof(struct entry))) == NULL) { 571 fprintf(stderr,"%s: unable to malloc space for permitted host entry\n", 572 progname); 573 exit(1); 574 } /* if */ 575 576 new_entry->host_addr = host_addr; 577 key = HASH(host_addr) % TABLE_SIZE; 578 new_entry->next = permitted_hosts[key]; 579 permitted_hosts[key] = new_entry; 580 } /* if */ 581 582} /* add_host */ 583 584 585/* 586 setup_table -- initialize the table of hosts allowed to contact the server, 587 by reading from the file specified by the GNU_SECURE 588 environment variable 589 Put in the local machine, and, if a security file is specifed, 590 add each host that is named in the file. 591 Return the number of hosts added. 592*/ 593static int 594setup_table (void) 595{ 596 FILE *host_file; 597 char *file_name; 598 char hostname[HOSTNAMSZ]; 599 u_int host_addr; 600 int i, hosts=0; 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 ((host_addr = internet_addr(hostname)) == -1) 609 { 610 fprintf(stderr,"%s: unable to find %s in /etc/hosts or from YP", 611 progname,hostname); 612 exit(1); 613 } /* if */ 614 615#ifdef AUTH_MAGIC_COOKIE 616 617 server_xauth = XauGetAuthByAddr (FamilyInternet, 618 sizeof(host_addr), (char *)&host_addr, 619 strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN, 620 strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME); 621 hosts++; 622 623#endif /* AUTH_MAGIC_COOKIE */ 624 625 626#if 0 /* Don't even want to allow access from the local host by default */ 627 add_host(host_addr); /* add local host */ 628#endif 629 630 if (((file_name = getenv("GNU_SECURE")) != NULL && /* security file */ 631 (host_file = fopen(file_name,"r")) != NULL)) /* opened ok */ 632 { 633 while ((fscanf(host_file,"%s",hostname) != EOF)) /* find a host */ 634 if ((host_addr = internet_addr(hostname)) != -1)/* get its addr */ 635 { 636 add_host(host_addr); /* add the addr */ 637 hosts++; 638 } 639 fclose(host_file); 640 } /* if */ 641 642 return hosts; 643} /* setup_table */ 644 645 646/* 647 internet_init -- initialize server, returning an internet socket that can 648 be listened on. 649*/ 650static int 651internet_init (void) 652{ 653 int ls; /* socket descriptor */ 654 struct servent *sp; /* pointer to service information */ 655 struct sockaddr_in server; /* for local socket address */ 656 char *ptr; /* ptr to return from getenv */ 657 658 if (setup_table() == 0) 659 return -1; 660 661 /* clear out address structure */ 662 memset (&server, '\0', sizeof (server)); 663 664 /* Set up address structure for the listen socket. */ 665 server.sin_family = AF_INET; 666 server.sin_addr.s_addr = INADDR_ANY; 667 668 /* Find the information for the gnu server 669 * in order to get the needed port number. 670 */ 671 if ((ptr=getenv("GNU_PORT")) != NULL) 672 server.sin_port = htons(atoi(ptr)); 673 else if ((sp = getservbyname ("gnuserv", "tcp")) == NULL) 674 server.sin_port = htons(DEFAULT_PORT+getuid()); 675 else 676 server.sin_port = sp->s_port; 677 678 /* Create the listen socket. */ 679 if ((ls = socket (AF_INET,SOCK_STREAM, 0)) == -1) 680 { 681 perror(progname); 682 fprintf(stderr,"%s: unable to create socket\n",progname); 683 exit(1); 684 } /* if */ 685 686 /* Bind the listen address to the socket. */ 687 if (bind(ls,(struct sockaddr *) &server,sizeof(struct sockaddr_in)) == -1) 688 { 689 perror(progname); 690 fprintf(stderr,"%s: unable to bind socket\n",progname); 691 exit(1); 692 } /* if */ 693 694 /* Initiate the listen on the socket so remote users 695 * can connect. 696 */ 697 if (listen(ls,20) == -1) 698 { 699 perror(progname); 700 fprintf(stderr,"%s: unable to listen\n",progname); 701 exit(1); 702 } /* if */ 703 704 return(ls); 705 706} /* internet_init */ 707 708 709/* 710 handle_internet_request -- accept a request from a client and send the information 711 to stdout (the gnu process). 712*/ 713static void 714handle_internet_request (int ls) 715{ 716 int s; 717 socklen_t addrlen = sizeof (struct sockaddr_in); 718 struct sockaddr_in peer; /* for peer socket address */ 719 720 memset (&peer, '\0', sizeof (peer)); 721 722 if ((s = accept(ls,(struct sockaddr *)&peer, &addrlen)) == -1) 723 { 724 perror(progname); 725 fprintf(stderr,"%s: unable to accept\n",progname); 726 exit(1); 727 } /* if */ 728 729 /* Check that access is allowed - if not return crud to the client */ 730 if (!permitted(peer.sin_addr.s_addr, s)) 731 { 732 send_string(s,"gnudoit: Connection refused\ngnudoit: unable to connect to remote"); 733 close(s); 734 735 printf("Refused connection from %s\004\n", inet_ntoa(peer.sin_addr)); 736 return; 737 } /* if */ 738 739 echo_request(s); 740 741} /* handle_internet_request */ 742#endif /* INTERNET_DOMAIN_SOCKETS */ 743 744 745#ifdef UNIX_DOMAIN_SOCKETS 746/* 747 unix_init -- initialize server, returning an unix-domain socket that can 748 be listened on. 749*/ 750static int 751unix_init (void) 752{ 753 int ls; /* socket descriptor */ 754 struct sockaddr_un server; /* unix socket address */ 755 socklen_t bindlen; 756 757 if ((ls = socket(AF_UNIX,SOCK_STREAM, 0)) < 0) 758 { 759 perror(progname); 760 fprintf(stderr,"%s: unable to create socket\n",progname); 761 exit(1); 762 } /* if */ 763 764 /* Set up address structure for the listen socket. */ 765#ifdef HIDE_UNIX_SOCKET 766 sprintf(server.sun_path,"%s/gsrvdir%d",tmpdir,(int)geteuid()); 767 if (mkdir(server.sun_path, 0700) < 0) 768 { 769 /* assume it already exists, and try to set perms */ 770 if (chmod(server.sun_path, 0700) < 0) 771 { 772 perror(progname); 773 fprintf(stderr,"%s: can't set permissions on %s\n", 774 progname, server.sun_path); 775 exit(1); 776 } 777 } 778 strcat(server.sun_path,"/gsrv"); 779 unlink(server.sun_path); /* remove old file if it exists */ 780#else /* HIDE_UNIX_SOCKET */ 781 sprintf(server.sun_path,"%s/gsrv%d",tmpdir,(int)geteuid()); 782 unlink(server.sun_path); /* remove old file if it exists */ 783#endif /* HIDE_UNIX_SOCKET */ 784 785 server.sun_family = AF_UNIX; 786#ifdef HAVE_SOCKADDR_SUN_LEN 787 /* See W. R. Stevens "Advanced Programming in the Unix Environment" 788 p. 502 */ 789 bindlen = (sizeof (server.sun_len) + sizeof (server.sun_family) 790 + strlen (server.sun_path) + 1); 791 server.sun_len = bindlen; 792#else 793 bindlen = sizeof(server); 794#endif 795 796 if (bind(ls,(struct sockaddr *)&server,bindlen) < 0) 797 { 798 perror(progname); 799 fprintf(stderr,"%s: unable to bind socket\n",progname); 800 exit(1); 801 } /* if */ 802 803 chmod(server.sun_path,0700); /* only this user can send commands */ 804 805 if (listen(ls,20) < 0) { 806 perror(progname); 807 fprintf(stderr,"%s: unable to listen\n",progname); 808 exit(1); 809 } /* if */ 810 811 /* #### there are also better ways of dealing with this when 812 sigvec() is present. */ 813#if defined (HAVE_SIGPROCMASK) 814 { 815 sigset_t _mask; 816 sigemptyset (&_mask); 817 sigaddset (&_mask, SIGPIPE); 818 sigprocmask (SIG_BLOCK, &_mask, NULL); 819 } 820#else 821 signal(SIGPIPE,SIG_IGN); /* in case user kills client */ 822#endif 823 824 return(ls); 825 826} /* unix_init */ 827 828 829/* 830 handle_unix_request -- accept a request from a client and send the information 831 to stdout (the gnu process). 832*/ 833static void 834handle_unix_request (int ls) 835{ 836 int s; 837 socklen_t len = sizeof (struct sockaddr_un); 838 struct sockaddr_un server; /* for unix socket address */ 839 840 server.sun_family = AF_UNIX; 841 842 if ((s = accept(ls,(struct sockaddr *)&server, &len)) < 0) 843 { 844 perror(progname); 845 fprintf(stderr,"%s: unable to accept\n",progname); 846 } /* if */ 847 848 echo_request(s); 849 850} /* handle_unix_request */ 851#endif /* UNIX_DOMAIN_SOCKETS */ 852 853 854int 855main (int argc, char *argv[]) 856{ 857 int chan; /* temporary channel number */ 858#ifdef SYSV_IPC 859 struct msgbuf *msgp; /* message buffer */ 860#else 861 int ils = -1; /* internet domain listen socket */ 862 int uls = -1; /* unix domain listen socket */ 863#endif /* SYSV_IPC */ 864 865 progname = argv[0]; 866 867 for(chan=3; chan < _NFILE; close(chan++)) /* close unwanted channels */ 868 ; 869 870#ifdef USE_TMPDIR 871 tmpdir = getenv("TMPDIR"); 872#endif 873 if (!tmpdir) 874 tmpdir = "/tmp"; 875#ifdef USE_LITOUT 876 { 877 /* this is to allow ^D to pass to emacs */ 878 int d = LLITOUT; 879 (void) ioctl(fileno(stdout), TIOCLBIS, &d); 880 } 881#endif 882 883#ifdef SYSV_IPC 884 ipc_init(&msgp); /* get a msqid to listen on, and a message buffer */ 885#endif /* SYSV_IPC */ 886 887#ifdef INTERNET_DOMAIN_SOCKETS 888 ils = internet_init(); /* get an internet domain socket to listen on */ 889#endif /* INTERNET_DOMAIN_SOCKETS */ 890 891#ifdef UNIX_DOMAIN_SOCKETS 892 uls = unix_init(); /* get a unix domain socket to listen on */ 893#endif /* UNIX_DOMAIN_SOCKETS */ 894 895 while (1) { 896#ifdef SYSV_IPC 897 handle_ipc_request(msgp); 898#else /* NOT SYSV_IPC */ 899 fd_set rmask; 900 FD_ZERO(&rmask); 901 FD_SET(fileno(stdin), &rmask); 902 if (uls >= 0) 903 FD_SET(uls, &rmask); 904 if (ils >= 0) 905 FD_SET(ils, &rmask); 906 907 if (select(max2(fileno(stdin),max2(uls,ils)) + 1, &rmask, 908 (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL) < 0) 909 { 910 perror(progname); 911 fprintf(stderr,"%s: unable to select\n",progname); 912 return 1; 913 } /* if */ 914 915#ifdef UNIX_DOMAIN_SOCKETS 916 if (uls > 0 && FD_ISSET(uls, &rmask)) 917 handle_unix_request(uls); 918#endif 919 920#ifdef INTERNET_DOMAIN_SOCKETS 921 if (ils > 0 && FD_ISSET(ils, &rmask)) 922 handle_internet_request(ils); 923#endif /* INTERNET_DOMAIN_SOCKETS */ 924 925 if (FD_ISSET(fileno(stdin), &rmask)) /* from stdin (gnu process) */ 926 handle_response(); 927#endif /* NOT SYSV_IPC */ 928 } /* while (1) */ 929} /* main */ 930 931#endif /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */ 932