Mercurial > hg > xemacs-beta
comparison lib-src/emacsserver.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 7e54bd776075 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* Communication subprocess for GNU Emacs acting as server. | |
2 Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* Synched up with: FSF 19.28. */ | |
22 | |
23 /* The GNU Emacs edit server process is run as a subprocess of Emacs | |
24 under control of the file lisp/server.el. | |
25 This program accepts communication from client (program emacsclient.c) | |
26 and passes their commands (consisting of keyboard characters) | |
27 up to the Emacs which then executes them. */ | |
28 | |
29 #define NO_SHORTNAMES | |
30 #include <../src/config.h> | |
31 #undef read | |
32 #undef write | |
33 #undef open | |
34 #undef close | |
35 #undef signal | |
36 | |
37 #if __STDC__ || defined(STDC_HEADERS) | |
38 # include <stdlib.h> | |
39 # include <unistd.h> | |
40 # include <fcntl.h> /* for creat() */ | |
41 # include <string.h> | |
42 #else | |
43 extern int errno; | |
44 #endif | |
45 | |
46 #if !defined(HAVE_SOCKETS) && !defined(HAVE_SYSVIPC) | |
47 #include <stdio.h> | |
48 | |
49 void | |
50 main () | |
51 { | |
52 fprintf (stderr, "Sorry, the Emacs server is supported only on systems\n"); | |
53 fprintf (stderr, "with Berkeley sockets or System V IPC.\n"); | |
54 exit (1); | |
55 } | |
56 | |
57 #else /* HAVE_SOCKETS or HAVE_SYSVIPC */ | |
58 | |
59 #if ! defined (HAVE_SYSVIPC) | |
60 /* BSD code is very different from SYSV IPC code */ | |
61 | |
62 #include <sys/types.h> | |
63 #include <sys/file.h> | |
64 #include <sys/socket.h> | |
65 #include <sys/signal.h> | |
66 #include <sys/stat.h> /* Needed for chmod, at least on Linux */ | |
67 #include <sys/un.h> | |
68 #include <stdio.h> | |
69 #include <errno.h> | |
70 #include "../src/sysproc.h" /* Needed for select */ | |
71 | |
72 void | |
73 main () | |
74 { | |
75 char system_name[256]; | |
76 int s, infd, fromlen; | |
77 struct sockaddr_un server, fromunix; | |
78 char *str, string[BUFSIZ], code[BUFSIZ]; | |
79 FILE *infile; | |
80 FILE **openfiles; | |
81 int openfiles_size; | |
82 | |
83 openfiles_size = 20; | |
84 openfiles = (FILE **) malloc (openfiles_size * sizeof (FILE *)); | |
85 if (openfiles == 0) | |
86 abort (); | |
87 | |
88 /* | |
89 * Open up an AF_UNIX socket in this person's home directory | |
90 */ | |
91 | |
92 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) | |
93 { | |
94 perror ("socket"); | |
95 exit (1); | |
96 } | |
97 memset (&server, 0, sizeof (server)); | |
98 server.sun_family = AF_UNIX; | |
99 #ifndef SERVER_HOME_DIR | |
100 gethostname (system_name, sizeof (system_name)); | |
101 sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name); | |
102 | |
103 if (unlink (server.sun_path) == -1 && errno != ENOENT) | |
104 { | |
105 perror ("unlink"); | |
106 exit (1); | |
107 } | |
108 #else | |
109 { | |
110 char *homedir; | |
111 | |
112 if ((homedir = getenv ("HOME")) == NULL) | |
113 { | |
114 fprintf (stderr,"No home directory\n"); | |
115 exit (1); | |
116 } | |
117 sprintf (server.sun_path, "/tmp/esrv%d", geteuid ()); | |
118 #if 0 | |
119 strcpy (server.sun_path, homedir); | |
120 strcat (server.sun_path, "/.emacs_server"); | |
121 #endif | |
122 /* Delete anyone else's old server. */ | |
123 unlink (server.sun_path); | |
124 } | |
125 #endif /* SERVER_HOME_DIR */ | |
126 | |
127 { | |
128 int bindlen; | |
129 | |
130 #ifdef HAVE_SOCKADDR_SUN_LEN | |
131 /* See W. R. Stevens "Advanced Programming in the Unix Environment" | |
132 p. 502 */ | |
133 bindlen = (sizeof (server.sun_len) + sizeof (server.sun_family) | |
134 + strlen (server.sun_path) + 1); | |
135 server.sun_len = bindlen; | |
136 #else | |
137 bindlen = strlen (server.sun_path) + sizeof (server.sun_family); | |
138 #endif | |
139 | |
140 if (bind (s, (struct sockaddr *) &server, bindlen) < 0) | |
141 { | |
142 perror ("bind"); | |
143 exit (1); | |
144 } | |
145 } | |
146 /* Only this user can send commands to this Emacs. */ | |
147 chmod (server.sun_path, 0600); | |
148 /* | |
149 * Now, just wait for everything to come in.. | |
150 */ | |
151 if (listen (s, 5) < 0) | |
152 { | |
153 perror ("listen"); | |
154 exit (1); | |
155 } | |
156 | |
157 /* Disable sigpipes in case luser kills client... */ | |
158 signal (SIGPIPE, SIG_IGN); | |
159 for (;;) | |
160 { | |
161 int rmask = (1 << s) + 1; | |
162 if (select (s + 1, (fd_set *)&rmask, 0, 0, 0) < 0) | |
163 perror ("select"); | |
164 if (rmask & (1 << s)) /* client sends list of filenames */ | |
165 { | |
166 fromlen = sizeof (fromunix); | |
167 fromunix.sun_family = AF_UNIX; | |
168 infd = accept (s, (struct sockaddr *) &fromunix, | |
169 #ifdef HAVE_POSIX_ACCEPT | |
170 /* Posix dictates that this arg should be | |
171 a size_t *, but all known existing | |
172 implementations want an int *. */ | |
173 (size_t *) &fromlen | |
174 #else | |
175 &fromlen | |
176 #endif | |
177 ); | |
178 if (infd < 0) | |
179 { | |
180 if (errno == EMFILE || errno == ENFILE) | |
181 printf ("Too many clients.\n"); | |
182 else | |
183 perror ("accept"); | |
184 continue; | |
185 } | |
186 | |
187 if (infd >= openfiles_size) | |
188 { | |
189 openfiles_size *= 2; | |
190 openfiles = (FILE **) realloc (openfiles, | |
191 openfiles_size * sizeof (FILE *)); | |
192 if (openfiles == 0) | |
193 abort (); | |
194 } | |
195 | |
196 infile = (FILE *) fdopen (infd, "r+"); /* open stream */ | |
197 if (infile == NULL) | |
198 { | |
199 printf ("Too many clients.\n"); | |
200 write (infd, "Too many clients.\n", 18); | |
201 close (infd); /* Prevent descriptor leak.. */ | |
202 continue; | |
203 } | |
204 str = fgets (string, BUFSIZ, infile); | |
205 if (str == NULL) | |
206 { | |
207 perror ("fgets"); | |
208 close (infd); /* Prevent descriptor leak.. */ | |
209 continue; | |
210 } | |
211 openfiles[infd] = infile; | |
212 printf ("Client: %d %s", infd, string); | |
213 /* If what we read did not end in a newline, | |
214 it means there is more. Keep reading from the socket | |
215 and outputting to Emacs, until we get the newline. */ | |
216 while (string[strlen (string) - 1] != '\n') | |
217 { | |
218 if (fgets (string, BUFSIZ, infile) == 0) | |
219 break; | |
220 printf ("%s", string); | |
221 } | |
222 fflush (stdout); | |
223 fflush (infile); | |
224 continue; | |
225 } | |
226 else if (rmask & 1) /* emacs sends codeword, fd, and string message */ | |
227 { | |
228 /* Read command codeword and fd */ | |
229 clearerr (stdin); | |
230 scanf ("%s %d%*c", code, &infd); | |
231 | |
232 if (ferror (stdin) || feof (stdin)) | |
233 { | |
234 fprintf (stderr, "server: error reading from standard input\n"); | |
235 exit (1); | |
236 } | |
237 | |
238 /* Transfer text from Emacs to the client, up to a newline. */ | |
239 infile = openfiles[infd]; | |
240 while (1) | |
241 { | |
242 if (fgets (string, BUFSIZ, stdin) == 0) | |
243 break; | |
244 fprintf (infile, "%s", string); | |
245 if (string[strlen (string) - 1] == '\n') | |
246 break; | |
247 } | |
248 fflush (infile); | |
249 | |
250 /* If command is close, close connection to client. */ | |
251 if (strncmp (code, "Close:", 6) == 0) | |
252 if (infd > 2) | |
253 { | |
254 fclose (infile); | |
255 close (infd); | |
256 } | |
257 continue; | |
258 } | |
259 } | |
260 } | |
261 | |
262 #else /* This is the SYSV IPC section */ | |
263 | |
264 #include <sys/types.h> | |
265 #include <sys/signal.h> | |
266 #include <sys/ipc.h> | |
267 #include <sys/msg.h> | |
268 #include <setjmp.h> | |
269 | |
270 jmp_buf msgenv; | |
271 | |
272 static SIGTYPE | |
273 msgcatch (int arg) | |
274 { | |
275 longjmp (msgenv, 1); | |
276 } | |
277 | |
278 | |
279 /* "THIS has to be fixed. Remember, stderr may not exist...-rlk." | |
280 Incorrect. This program runs as an inferior of Emacs. | |
281 Its stderr always exists--rms. */ | |
282 #include <stdio.h> | |
283 | |
284 #if !__STDC__ && !defined(STDC_HEADERS) | |
285 #ifndef convex | |
286 char *getenv (); | |
287 #endif | |
288 #endif | |
289 | |
290 void | |
291 main () | |
292 { | |
293 int s, fromlen, ioproc; | |
294 #if 0 | |
295 int infd; | |
296 #endif /* 0 */ | |
297 key_t key; | |
298 struct msgbuf * msgp = | |
299 (struct msgbuf *) malloc (sizeof *msgp + BUFSIZ); | |
300 struct msqid_ds msg_st; | |
301 int p; | |
302 char *homedir; | |
303 char string[BUFSIZ]; | |
304 #if 0 | |
305 FILE *infile; | |
306 #endif /* 0 */ | |
307 | |
308 /* | |
309 * Create a message queue using ~/.emacs_server as the path for ftok | |
310 */ | |
311 if ((homedir = getenv ("HOME")) == NULL) | |
312 { | |
313 fprintf (stderr,"No home directory\n"); | |
314 exit (1); | |
315 } | |
316 strcpy (string, homedir); | |
317 strcat (string, "/.emacs_server"); | |
318 creat (string, 0600); | |
319 key = ftok (string, 1); /* unlikely to be anyone else using it */ | |
320 s = msgget (key, 0600 | IPC_CREAT); | |
321 if (s == -1) | |
322 { | |
323 perror ("msgget"); | |
324 exit (1); | |
325 } | |
326 | |
327 /* Fork so we can close connection even if parent dies */ | |
328 p = fork (); | |
329 if (setjmp (msgenv)) | |
330 { | |
331 msgctl (s, IPC_RMID, 0); | |
332 kill (p, SIGKILL); | |
333 exit (0); | |
334 } | |
335 signal (SIGTERM, msgcatch); | |
336 signal (SIGINT, msgcatch); | |
337 if (p > 0) | |
338 { | |
339 /* This is executed in the original process that did the fork above. */ | |
340 /* Get pid of Emacs itself. */ | |
341 p = getppid (); | |
342 setpgrp (); /* Gnu kills process group on exit */ | |
343 while (1) | |
344 { | |
345 /* Is Emacs still alive? */ | |
346 if (kill (p, 0) < 0) | |
347 { | |
348 msgctl (s, IPC_RMID, 0); | |
349 exit (0); | |
350 } | |
351 sleep (10); | |
352 } | |
353 } | |
354 | |
355 /* This is executed in the child made by forking above. | |
356 Call it c1. Make another process, ioproc. */ | |
357 | |
358 ioproc = fork (); | |
359 if (ioproc == 0) | |
360 { | |
361 /* In process ioproc, wait for text from Emacs, | |
362 and send it to the process c1. | |
363 This way, c1 only has to wait for one source of input. */ | |
364 while (fgets (msgp->mtext, BUFSIZ, stdin)) | |
365 { | |
366 msgp->mtype = 1; | |
367 msgsnd (s, msgp, strlen (msgp->mtext) + 1, 0); | |
368 } | |
369 exit (1); | |
370 } | |
371 | |
372 /* In the process c1, | |
373 listen for messages from clients and pass them to Emacs. */ | |
374 while (1) | |
375 { | |
376 if ((fromlen = msgrcv (s, msgp, BUFSIZ - 1, 1, 0)) < 0) | |
377 { | |
378 perror ("msgrcv"); | |
379 exit (1); | |
380 } | |
381 else | |
382 { | |
383 msgctl (s, IPC_STAT, &msg_st); | |
384 | |
385 /* Distinguish whether the message came from a client, or from | |
386 ioproc. */ | |
387 if (msg_st.msg_lspid == ioproc) | |
388 { | |
389 char code[BUFSIZ]; | |
390 int inproc; | |
391 | |
392 /* Message from ioproc: tell a client we are done. */ | |
393 msgp->mtext[strlen (msgp->mtext)-1] = 0; | |
394 sscanf (msgp->mtext, "%s %d", code, &inproc); | |
395 msgp->mtype = inproc; | |
396 msgsnd (s, msgp, strlen (msgp->mtext) + 1, 0); | |
397 continue; | |
398 } | |
399 | |
400 /* This is a request from a client: copy to stdout | |
401 so that Emacs will get it. Include msg_lspid | |
402 so server.el can tell us where to send the reply. */ | |
403 strncpy (string, msgp->mtext, fromlen); | |
404 string[fromlen] = 0; /* make sure */ | |
405 /* Newline is part of string.. */ | |
406 printf ("Client: %d %s", (int) msg_st.msg_lspid, string); | |
407 fflush (stdout); | |
408 /* Now, wait for a wakeup */ | |
409 } | |
410 } | |
411 } | |
412 | |
413 #endif /* HAVE_SYSVIPC */ | |
414 | |
415 #endif /* HAVE_SOCKETS or HAVE_SYSVIPC */ |