Mercurial > hg > xemacs-beta
annotate lib-src/gnuslib.c @ 5290:e6508b64ee08
More permission consistency.
author | Stephen J. Turnbull <stephen@xemacs.org> |
---|---|
date | Mon, 14 Jun 2010 19:03:57 +0900 |
parents | 2161ac78b41e |
children | b9167d522a9a |
rev | line source |
---|---|
428 | 1 /* -*-C-*- |
613 | 2 Common library code for the XEmacs server and client. |
428 | 3 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
4 Copyright (C) 1989 Free Software Foundation, Inc. |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
5 |
613 | 6 This file is part of XEmacs. |
428 | 7 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
8 XEmacs is free software; you can redistribute it and/or modify it |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
9 under the terms of the GNU General Public License as published by |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
10 the Free Software Foundation; either version 2, or (at your option) |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
11 any later version. |
428 | 12 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
13 XEmacs is distributed in the hope that it will be useful, but |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
14 WITHOUT ANY WARRANTY; without even the implied warranty of |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
16 General Public License for more details. |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
17 |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
18 You should have received a copy of the GNU General Public License |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
19 along with XEmacs; see the file COPYING. If not, write to the Free |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
3556
diff
changeset
|
21 Boston, MA 02110-1301, USA. |
428 | 22 |
23 Author: Andy Norman (ange@hplb.hpl.hp.com), based on | |
24 'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU | |
25 Emacs distribution. | |
26 | |
27 Please mail bugs and suggestions to the author at the above address. | |
28 */ | |
29 | |
30 /* HISTORY | |
31 * 11-Nov-1990 bristor@simba | |
32 * Added EOT stuff. | |
33 */ | |
34 | |
35 /* | |
36 * This file incorporates new features added by Bob Weiner <weiner@mot.com>, | |
37 * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>. | |
38 * Please see the note at the end of the README file for details. | |
39 * | |
40 * (If gnuserv came bundled with your emacs, the README file is probably | |
41 * ../etc/gnuserv.README relative to the directory containing this file) | |
42 */ | |
43 | |
44 #if 0 | |
45 static char rcsid [] = "!Header: gnuslib.c,v 2.4 95/02/16 11:57:37 arup alpha !"; | |
46 #endif | |
47 | |
48 #include "gnuserv.h" | |
49 #include <errno.h> | |
50 | |
51 #ifdef SYSV_IPC | |
52 static int connect_to_ipc_server (void); | |
53 #endif | |
54 #ifdef UNIX_DOMAIN_SOCKETS | |
55 static int connect_to_unix_server (void); | |
56 #endif | |
57 #ifdef INTERNET_DOMAIN_SOCKETS | |
458 | 58 static int connect_to_internet_server (char *serverhost, unsigned short port); |
428 | 59 #endif |
60 | |
61 /* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */ | |
62 #ifdef HAVE_BROKEN_INET_ADDR | |
63 # define IN_ADDR struct in_addr | |
64 # define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1) | |
65 #else | |
66 # if (LONGBITS > 32) | |
67 # define IN_ADDR unsigned int | |
68 # else | |
69 # define IN_ADDR unsigned long | |
70 # endif | |
71 # define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) -1) | |
72 #endif | |
73 | |
74 #include <stdlib.h> | |
75 #include <stdio.h> | |
76 #include <sys/types.h> | |
77 #include <sys/stat.h> | |
78 #ifdef HAVE_UNISTD_H | |
79 #include <unistd.h> | |
80 #endif /* HAVE_UNISTD_H */ | |
81 #ifdef HAVE_STRING_H | |
82 #include <string.h> | |
83 #endif /* HAVE_STRING_H */ | |
84 | |
85 #include <arpa/inet.h> | |
86 | |
87 char *tmpdir = NULL; | |
88 | |
89 char *progname = NULL; | |
90 | |
440 | 91 int |
92 make_connection (char *hostarg, int portarg, int *s) | |
428 | 93 { |
94 #ifdef INTERNET_DOMAIN_SOCKETS | |
95 char *ptr; | |
96 if (hostarg == NULL) | |
97 hostarg = getenv("GNU_HOST"); | |
98 if (portarg == 0 && (ptr=getenv("GNU_PORT")) != NULL) | |
99 portarg = atoi(ptr); | |
100 #endif | |
101 | |
102 if (hostarg != NULL) { | |
103 /* hostname was given explicitly, via cmd line arg or GNU_HOST, | |
104 * so obey it. */ | |
105 #ifdef UNIX_DOMAIN_SOCKETS | |
106 if (!strcmp(hostarg, "unix")) { | |
107 *s = connect_to_unix_server(); | |
108 return (int) CONN_UNIX; | |
109 } | |
110 #endif /* UNIX_DOMAIN_SOCKETS */ | |
111 #ifdef INTERNET_DOMAIN_SOCKETS | |
112 *s = connect_to_internet_server(hostarg, portarg); | |
113 return (int) CONN_INTERNET; | |
114 #endif | |
115 #ifdef SYSV_IPC | |
116 return -1; /* hostarg should always be NULL for SYSV_IPC */ | |
117 #endif | |
118 } else { | |
119 /* no hostname given. Use unix-domain/sysv-ipc, or | |
120 * internet-domain connection to local host if they're not available. */ | |
121 #if defined(UNIX_DOMAIN_SOCKETS) | |
122 *s = connect_to_unix_server(); | |
123 return (int) CONN_UNIX; | |
124 #elif defined(SYSV_IPC) | |
125 *s = connect_to_ipc_server(); | |
126 return (int) CONN_IPC; | |
127 #elif defined(INTERNET_DOMAIN_SOCKETS) | |
128 { | |
129 char localhost[HOSTNAMSZ]; | |
130 gethostname(localhost,HOSTNAMSZ); /* use this host by default */ | |
131 *s = connect_to_internet_server(localhost, portarg); | |
132 return (int) CONN_INTERNET; | |
133 } | |
134 #endif /* IPC type */ | |
135 } | |
136 } | |
137 | |
138 #ifdef SYSV_IPC | |
139 /* | |
140 connect_to_ipc_server -- establish connection with server process via SYSV IPC | |
141 Returns msqid for server if successful. | |
142 */ | |
440 | 143 static int |
144 connect_to_ipc_server (void) | |
428 | 145 { |
146 int s; /* connected msqid */ | |
147 key_t key; /* message key */ | |
148 char buf[GSERV_BUFSZ+1]; /* buffer for filename */ | |
149 | |
150 sprintf(buf,"%s/gsrv%d",tmpdir,(int)geteuid()); | |
151 creat(buf,0600); | |
152 if ((key = ftok(buf,1)) == -1) { | |
153 perror(progname); | |
154 fprintf(stderr, "%s: unable to get ipc key from %s\n", | |
155 progname, buf); | |
156 exit(1); | |
157 } | |
158 | |
159 if ((s = msgget(key,0600)) == -1) { | |
160 perror(progname); | |
161 fprintf(stderr,"%s: unable to access msg queue\n",progname); | |
162 exit(1); | |
163 }; /* if */ | |
164 | |
165 return(s); | |
166 | |
167 } /* connect_to_ipc_server */ | |
168 | |
169 | |
170 /* | |
171 disconnect_from_ipc_server -- inform the server that sending has finished, | |
172 and wait for its reply. | |
173 */ | |
440 | 174 void |
175 disconnect_from_ipc_server (int s, struct msgbuf *msgp, int echo) | |
428 | 176 { |
177 int len; /* length of received message */ | |
178 | |
179 send_string(s,EOT_STR); /* EOT terminates this message */ | |
180 msgp->mtype = 1; | |
181 | |
182 if(msgsnd(s,msgp,strlen(msgp->mtext)+1,0) < 0) { | |
183 perror(progname); | |
184 fprintf(stderr,"%s: unable to send message to server\n",progname); | |
185 exit(1); | |
186 }; /* if */ | |
187 | |
188 if((len = msgrcv(s,msgp,GSERV_BUFSZ,getpid(),0)) < 0) { | |
189 perror(progname); | |
190 fprintf(stderr,"%s: unable to receive message from server\n",progname); | |
191 exit(1); | |
192 }; /* if */ | |
193 | |
194 if (echo) { | |
195 msgp->mtext[len] = '\0'; /* string terminate message */ | |
196 fputs(msgp->mtext, stdout); | |
197 if (msgp->mtext[len-1] != '\n') putchar ('\n'); | |
198 }; /* if */ | |
199 | |
200 } /* disconnect_from_ipc_server */ | |
201 #endif /* SYSV_IPC */ | |
202 | |
203 | |
204 #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS) | |
205 /* | |
206 send_string -- send string to socket. | |
207 */ | |
440 | 208 void |
442 | 209 send_string (int s, const char *msg) |
428 | 210 { |
211 #if 0 | |
212 if (send(s,msg,strlen(msg),0) < 0) { | |
213 perror(progname); | |
214 fprintf(stderr,"%s: unable to send\n",progname); | |
215 exit(1); | |
216 }; /* if */ | |
217 #else | |
218 int len, left=strlen(msg); | |
219 while (left > 0) { | |
220 if ((len=write(s,msg,min2(left,GSERV_BUFSZ))) < 0) { | |
221 /* XEmacs addition: robertl@arnet.com */ | |
222 if (errno == EPIPE) { | |
223 return ; | |
224 } | |
225 perror(progname); | |
226 fprintf(stderr,"%s: unable to send\n",progname); | |
227 exit(1); | |
228 }; /* if */ | |
229 left -= len; | |
230 msg += len; | |
231 }; /* while */ | |
232 #endif | |
233 } /* send_string */ | |
234 | |
235 /* | |
236 read_line -- read a \n terminated line from a socket | |
237 */ | |
440 | 238 int |
239 read_line (int s, char *dest) | |
428 | 240 { |
241 int length; | |
242 int offset=0; | |
243 char buffer[GSERV_BUFSZ+1]; | |
244 | |
245 while ((length=read(s,buffer+offset,1)>0) && buffer[offset]!='\n' | |
246 && buffer[offset] != EOT_CHR) { | |
247 offset += length; | |
248 if (offset >= GSERV_BUFSZ) | |
249 break; | |
250 } | |
251 buffer[offset] = '\0'; | |
252 strcpy(dest,buffer); | |
253 return 1; | |
254 } /* read_line */ | |
255 #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */ | |
256 | |
257 | |
258 #ifdef UNIX_DOMAIN_SOCKETS | |
259 /* | |
260 connect_to_unix_server -- establish connection with server process via a unix- | |
261 domain socket. Returns socket descriptor for server | |
262 if successful. | |
263 */ | |
440 | 264 static int |
265 connect_to_unix_server (void) | |
428 | 266 { |
267 int s; /* connected socket descriptor */ | |
268 struct sockaddr_un server; /* for unix connections */ | |
269 | |
270 if ((s = socket(AF_UNIX,SOCK_STREAM,0)) < 0) { | |
271 perror(progname); | |
272 fprintf(stderr,"%s: unable to create socket\n",progname); | |
273 exit(1); | |
274 }; /* if */ | |
275 | |
276 server.sun_family = AF_UNIX; | |
277 #ifdef HIDE_UNIX_SOCKET | |
278 sprintf(server.sun_path,"%s/gsrvdir%d/gsrv",tmpdir,(int)geteuid()); | |
279 #else /* HIDE_UNIX_SOCKET */ | |
280 sprintf(server.sun_path,"%s/gsrv%d",tmpdir,(int)geteuid()); | |
281 #endif /* HIDE_UNIX_SOCKET */ | |
282 if (connect(s,(struct sockaddr *)&server,strlen(server.sun_path)+2) < 0) { | |
283 perror(progname); | |
284 fprintf(stderr,"%s: unable to connect to local\n",progname); | |
285 exit(1); | |
286 }; /* if */ | |
287 | |
288 return(s); | |
289 | |
290 } /* connect_to_unix_server */ | |
291 #endif /* UNIX_DOMAIN_SOCKETS */ | |
292 | |
293 | |
294 #ifdef INTERNET_DOMAIN_SOCKETS | |
295 /* | |
296 internet_addr -- return the internet addr of the hostname or | |
297 internet address passed. Return -1 on error. | |
298 */ | |
440 | 299 int |
300 internet_addr (char *host) | |
428 | 301 { |
302 struct hostent *hp; /* pointer to host info for remote host */ | |
303 IN_ADDR numeric_addr; /* host address */ | |
304 | |
305 numeric_addr = inet_addr(host); | |
306 if (!NUMERIC_ADDR_ERROR) | |
307 return numeric_addr; | |
308 else if ((hp = gethostbyname(host)) != NULL) | |
309 return ((struct in_addr *)(hp->h_addr))->s_addr; | |
310 else | |
311 return -1; | |
312 | |
313 } /* internet_addr */ | |
314 | |
315 #ifdef AUTH_MAGIC_COOKIE | |
316 # include <X11/X.h> | |
317 # include <X11/Xauth.h> | |
318 | |
319 static Xauth *server_xauth = NULL; | |
320 #endif | |
321 | |
322 /* | |
323 connect_to_internet_server -- establish connection with server process via | |
324 an internet domain socket. Returns socket | |
325 descriptor for server if successful. | |
326 */ | |
440 | 327 static int |
458 | 328 connect_to_internet_server (char *serverhost, unsigned short port) |
428 | 329 { |
330 int s; /* connected socket descriptor */ | |
331 struct servent *sp; /* pointer to service information */ | |
332 struct sockaddr_in peeraddr_in; /* for peer socket address */ | |
333 char buf[512]; /* temporary buffer */ | |
334 | |
335 /* clear out address structures */ | |
336 memset((char *)&peeraddr_in,0,sizeof(struct sockaddr_in)); | |
337 | |
338 /* Set up the peer address to which we will connect. */ | |
339 peeraddr_in.sin_family = AF_INET; | |
340 | |
341 /* look up the server host's internet address */ | |
647 | 342 if ((peeraddr_in.sin_addr.s_addr = internet_addr (serverhost)) == |
343 (unsigned int) -1) | |
344 { | |
345 fprintf (stderr, "%s: unable to find %s in /etc/hosts or from YP\n", | |
346 progname, serverhost); | |
347 exit(1); | |
348 } | |
428 | 349 |
350 if (port == 0) { | |
351 if ((sp = getservbyname ("gnuserv","tcp")) == NULL) | |
352 peeraddr_in.sin_port = htons(DEFAULT_PORT+getuid()); | |
353 else | |
354 peeraddr_in.sin_port = sp->s_port; | |
355 } /* if */ | |
356 else | |
357 peeraddr_in.sin_port = htons(port); | |
358 | |
359 /* Create the socket. */ | |
360 if ((s = socket (AF_INET,SOCK_STREAM, 0))== -1) { | |
361 perror(progname); | |
362 fprintf(stderr,"%s: unable to create socket\n",progname); | |
363 exit(1); | |
364 }; /* if */ | |
365 | |
366 /* Try to connect to the remote server at the address | |
367 * which was just built into peeraddr. | |
368 */ | |
369 if (connect(s, (struct sockaddr *)&peeraddr_in, | |
370 sizeof(struct sockaddr_in)) == -1) { | |
371 perror(progname); | |
372 fprintf(stderr, "%s: unable to connect to remote\n",progname); | |
373 exit(1); | |
374 }; /* if */ | |
375 | |
376 #ifdef AUTH_MAGIC_COOKIE | |
377 | |
378 /* send credentials using MIT-MAGIC-COOKIE-1 protocol */ | |
379 | |
380 server_xauth = | |
381 XauGetAuthByAddr(FamilyInternet, | |
382 sizeof(peeraddr_in.sin_addr.s_addr), | |
383 (char *) &peeraddr_in.sin_addr.s_addr, | |
384 strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN, | |
385 strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME); | |
386 | |
387 if (server_xauth && server_xauth->data) { | |
388 sprintf(buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length); | |
389 write (s, buf, strlen(buf)); | |
390 write (s, server_xauth->data, server_xauth->data_length); | |
391 | |
392 return (s); | |
393 } | |
394 | |
395 #endif /* AUTH_MAGIC_COOKIE */ | |
396 | |
397 sprintf (buf, "%s\n", DEFAUTH_NAME); | |
398 write (s, buf, strlen(buf)); | |
399 | |
400 return(s); | |
401 | |
402 } /* connect_to_internet_server */ | |
403 #endif /* INTERNET_DOMAIN_SOCKETS */ | |
404 | |
405 | |
406 #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS) | |
407 /* | |
408 disconnect_from_server -- inform the server that sending has finished, and wait for | |
409 its reply. | |
410 */ | |
440 | 411 void |
412 disconnect_from_server (int s, int echo) | |
428 | 413 { |
414 #if 0 | |
415 char buffer[REPLYSIZ+1]; | |
416 #else | |
417 char buffer[GSERV_BUFSZ+1]; | |
418 #endif | |
419 int add_newline = 1; | |
420 int length; | |
421 | |
422 send_string(s,EOT_STR); /* make sure server gets string */ | |
423 | |
3556 | 424 #ifndef _SCO_DS |
428 | 425 /* |
3556 | 426 * There used to be a comment here complaining about ancient Linux |
427 * versions. It is no longer relevant. I don't know why _SCO_DS is | |
428 * verboten here, as the original comment did not say. | |
428 | 429 */ |
430 | |
431 if (shutdown(s,1) == -1) { | |
432 perror(progname); | |
433 fprintf(stderr, "%s: unable to shutdown socket\n",progname); | |
434 exit(1); | |
435 }; /* if */ | |
436 #endif | |
437 | |
438 #if 0 | |
439 while((length = recv(s,buffer,REPLYSIZ,0)) > 0) { | |
440 buffer[length] = '\0'; | |
441 if (echo) fputs(buffer,stdout); | |
442 add_newline = (buffer[length-1] != '\n'); | |
443 }; /* while */ | |
444 #else | |
445 while ((length = read(s,buffer,GSERV_BUFSZ)) > 0 || | |
446 (length == -1 && errno == EINTR)) { | |
3556 | 447 if (length > 0) { |
428 | 448 buffer[length] = '\0'; |
449 if (echo) { | |
450 fputs(buffer,stdout); | |
451 add_newline = (buffer[length-1] != '\n'); | |
452 }; /* if */ | |
453 }; /* if */ | |
454 }; /* while */ | |
455 #endif | |
456 | |
457 if (echo && add_newline) putchar('\n'); | |
458 | |
459 if(length < 0) { | |
460 perror(progname); | |
461 fprintf(stderr,"%s: unable to read the reply from the server\n",progname); | |
462 exit(1); | |
463 }; /* if */ | |
464 | |
465 } /* disconnect_from_server */ | |
466 #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */ |