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