Mercurial > emacs
comparison lib-src/emacsserver.c @ 204:00dde7fa9e98
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 04 Mar 1991 02:59:40 +0000 |
parents | |
children | db84d8d9a1d9 |
comparison
equal
deleted
inserted
replaced
203:bc3eeb2182c8 | 204:00dde7fa9e98 |
---|---|
1 /* Communication subprocess for GNU Emacs acting as server. | |
2 Copyright (C) 1986, 1987 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 1, 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 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | |
20 | |
21 /* The GNU Emacs edit server process is run as a subprocess of Emacs | |
22 under control of the file lisp/server.el. | |
23 This program accepts communication from client (program emacsclient.c) | |
24 and passes their commands (consisting of keyboard characters) | |
25 up to the Emacs which then executes them. */ | |
26 | |
27 #define NO_SHORTNAMES | |
28 #include "../src/config.h" | |
29 #undef read | |
30 #undef write | |
31 #undef open | |
32 #undef close | |
33 | |
34 | |
35 #if !defined(HAVE_SOCKETS) && !defined(HAVE_SYSVIPC) | |
36 #include <stdio.h> | |
37 | |
38 main () | |
39 { | |
40 fprintf (stderr, "Sorry, the Emacs server is supported only on systems\n"); | |
41 fprintf (stderr, "with Berkeley sockets or System V IPC.\n"); | |
42 exit (1); | |
43 } | |
44 | |
45 #else /* HAVE_SOCKETS or HAVE_SYSVIPC */ | |
46 | |
47 #if ! defined (HAVE_SYSVIPC) | |
48 /* BSD code is very different from SYSV IPC code */ | |
49 | |
50 #include <sys/file.h> | |
51 #include <sys/types.h> | |
52 #include <sys/socket.h> | |
53 #include <sys/signal.h> | |
54 #include <sys/un.h> | |
55 #include <stdio.h> | |
56 #include <errno.h> | |
57 | |
58 extern int errno; | |
59 | |
60 main () | |
61 { | |
62 int s, infd, fromlen; | |
63 struct sockaddr_un server, fromunix; | |
64 char *homedir; | |
65 char *str, string[BUFSIZ], code[BUFSIZ]; | |
66 FILE *infile; | |
67 FILE **openfiles; | |
68 int openfiles_size; | |
69 | |
70 int geteuid (); | |
71 char *getenv (); | |
72 | |
73 openfiles_size = 20; | |
74 openfiles = (FILE **) malloc (openfiles_size * sizeof (FILE *)); | |
75 if (openfiles == 0) | |
76 abort (); | |
77 | |
78 /* | |
79 * Open up an AF_UNIX socket in this person's home directory | |
80 */ | |
81 | |
82 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) | |
83 { | |
84 perror ("socket"); | |
85 exit (1); | |
86 } | |
87 server.sun_family = AF_UNIX; | |
88 homedir = getenv ("HOME"); | |
89 if (homedir == NULL) | |
90 { | |
91 fprintf (stderr,"No home directory\n"); | |
92 exit (1); | |
93 } | |
94 sprintf (server.sun_path, "/tmp/esrv%d", geteuid ()); | |
95 | |
96 #if 0 | |
97 strcpy (server.sun_path, homedir); | |
98 strcat (server.sun_path, "/.emacs_server"); | |
99 #endif | |
100 | |
101 /* Delete anyone else's old server. */ | |
102 unlink (server.sun_path); | |
103 if (bind (s, &server, strlen (server.sun_path) + 2) < 0) | |
104 { | |
105 perror ("bind"); | |
106 exit (1); | |
107 } | |
108 /* Only this user can send commands to this Emacs. */ | |
109 chmod (server.sun_path, 0600); | |
110 /* | |
111 * Now, just wait for everything to come in.. | |
112 */ | |
113 if (listen (s, 5) < 0) | |
114 { | |
115 perror ("listen"); | |
116 exit (1); | |
117 } | |
118 | |
119 /* Disable sigpipes in case luser kills client... */ | |
120 signal (SIGPIPE, SIG_IGN); | |
121 for (;;) | |
122 { | |
123 int rmask = (1 << s) + 1; | |
124 if (select (s + 1, &rmask, 0, 0, 0) < 0) | |
125 perror ("select"); | |
126 if (rmask & (1 << s)) /* client sends list of filenames */ | |
127 { | |
128 fromlen = sizeof (fromunix); | |
129 fromunix.sun_family = AF_UNIX; | |
130 infd = accept (s, &fromunix, &fromlen); /* open socket fd */ | |
131 if (infd < 0) | |
132 { | |
133 if (errno == EMFILE || errno == ENFILE) | |
134 printf ("Too many clients.\n"); | |
135 else | |
136 perror ("accept"); | |
137 continue; | |
138 } | |
139 | |
140 if (infd >= openfiles_size) | |
141 { | |
142 openfiles_size *= 2; | |
143 openfiles = (FILE **) realloc (openfiles, | |
144 openfiles_size * sizeof (FILE *)); | |
145 if (openfiles == 0) | |
146 abort (); | |
147 } | |
148 | |
149 infile = fdopen (infd, "r+"); /* open stream */ | |
150 if (infile == NULL) | |
151 { | |
152 printf ("Too many clients.\n"); | |
153 write (infd, "Too many clients.\n", 18); | |
154 close (infd); /* Prevent descriptor leak.. */ | |
155 continue; | |
156 } | |
157 str = fgets (string, BUFSIZ, infile); | |
158 if (str == NULL) | |
159 { | |
160 perror ("fgets"); | |
161 close (infd); /* Prevent descriptor leak.. */ | |
162 continue; | |
163 } | |
164 openfiles[infd] = infile; | |
165 printf ("Client: %d %s", infd, string); | |
166 /* If what we read did not end in a newline, | |
167 it means there is more. Keep reading from the socket | |
168 and outputting to Emacs, until we get the newline. */ | |
169 while (string[strlen (string) - 1] != '\n') | |
170 { | |
171 if (fgets (string, BUFSIZ, infile) == 0) | |
172 break; | |
173 printf ("%s", string); | |
174 } | |
175 fflush (stdout); | |
176 fflush (infile); | |
177 continue; | |
178 } | |
179 else if (rmask & 1) /* emacs sends codeword, fd, and string message */ | |
180 { | |
181 /* Read command codeword and fd */ | |
182 clearerr (stdin); | |
183 scanf ("%s %d%*c", code, &infd); | |
184 if (ferror (stdin) || feof (stdin)) | |
185 { | |
186 fprintf (stderr, "server: error reading from standard input\n"); | |
187 exit (1); | |
188 } | |
189 | |
190 /* Transfer text from Emacs to the client, up to a newline. */ | |
191 infile = openfiles[infd]; | |
192 while (1) | |
193 { | |
194 if (fgets (string, BUFSIZ, stdin) == 0) | |
195 break; | |
196 fprintf (infile, "%s", string); | |
197 if (string[strlen (string) - 1] == '\n') | |
198 break; | |
199 } | |
200 fflush (infile); | |
201 | |
202 /* If command is close, close connection to client. */ | |
203 if (strncmp (code, "Close:", 6) == 0) | |
204 if (infd > 2) | |
205 { | |
206 fclose (infile); | |
207 close (infd); | |
208 } | |
209 continue; | |
210 } | |
211 } | |
212 } | |
213 | |
214 #else /* This is the SYSV IPC section */ | |
215 | |
216 #include <sys/types.h> | |
217 #include <sys/signal.h> | |
218 #include <sys/ipc.h> | |
219 #include <sys/msg.h> | |
220 #include <setjmp.h> | |
221 | |
222 jmp_buf msgenv; | |
223 | |
224 msgcatch () | |
225 { | |
226 longjmp (msgenv, 1); | |
227 } | |
228 | |
229 | |
230 /* "THIS has to be fixed. Remember, stderr may not exist...-rlk." | |
231 Incorrect. This program runs as an inferior of Emacs. | |
232 Its stderr always exists--rms. */ | |
233 #include <stdio.h> | |
234 | |
235 main () | |
236 { | |
237 int s, infd, fromlen; | |
238 key_t key; | |
239 struct msgbuf * msgp = | |
240 (struct msgbuf *) malloc (sizeof *msgp + BUFSIZ); | |
241 struct msqid_ds msg_st; | |
242 int p; | |
243 char *homedir, *getenv (); | |
244 char string[BUFSIZ]; | |
245 FILE *infile; | |
246 | |
247 /* | |
248 * Create a message queue using ~/.emacs_server as the path for ftok | |
249 */ | |
250 if ((homedir = getenv ("HOME")) == NULL) | |
251 { | |
252 fprintf (stderr,"No home directory\n"); | |
253 exit (1); | |
254 } | |
255 strcpy (string, homedir); | |
256 strcat (string, "/.emacs_server"); | |
257 creat (string, 0600); | |
258 key = ftok (string, 1); /* unlikely to be anyone else using it */ | |
259 s = msgget (key, 0600 | IPC_CREAT); | |
260 if (s == -1) | |
261 { | |
262 perror ("msgget"); | |
263 exit (1); | |
264 } | |
265 | |
266 /* Fork so we can close connection even if parent dies */ | |
267 p = fork (); | |
268 if (setjmp (msgenv)) | |
269 { | |
270 msgctl (s, IPC_RMID, 0); | |
271 kill (p, SIGKILL); | |
272 exit (0); | |
273 } | |
274 signal (SIGTERM, msgcatch); | |
275 signal (SIGINT, msgcatch); | |
276 /* If parent goes away, remove message box and exit */ | |
277 if (p == 0) | |
278 { | |
279 p = getppid (); | |
280 setpgrp (); /* Gnu kills process group on exit */ | |
281 while (1) | |
282 { | |
283 if (kill (p, 0) < 0) | |
284 { | |
285 msgctl (s, IPC_RMID, 0); | |
286 exit (0); | |
287 } | |
288 sleep (10); | |
289 } | |
290 } | |
291 | |
292 while (1) | |
293 { | |
294 if ((fromlen = msgrcv (s, msgp, BUFSIZ - 1, 1, 0)) < 0) | |
295 { | |
296 perror ("msgrcv"); | |
297 } | |
298 else | |
299 { | |
300 msgctl (s, IPC_STAT, &msg_st); | |
301 strncpy (string, msgp->mtext, fromlen); | |
302 string[fromlen] = 0; /* make sure */ | |
303 /* Newline is part of string.. */ | |
304 printf ("Client: %d %s", s, string); | |
305 fflush (stdout); | |
306 /* Now, wait for a wakeup */ | |
307 fgets (msgp->mtext, BUFSIZ, stdin); | |
308 msgp->mtext[strlen (msgp->mtext)-1] = 0; | |
309 /* strcpy (msgp->mtext, "done");*/ | |
310 msgp->mtype = msg_st.msg_lspid; | |
311 msgsnd (s, msgp, strlen (msgp->mtext)+1, 0); | |
312 } | |
313 } | |
314 } | |
315 | |
316 #endif /* HAVE_SYSVIPC */ | |
317 | |
318 #endif /* HAVE_SOCKETS or HAVE_SYSVIPC */ |