(quote_file_name): New function.
[bpt/emacs.git] / lib-src / emacsclient.c
1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #define NO_SHORTNAMES
23 #include <../src/config.h>
24 #undef read
25 #undef write
26 #undef open
27 #undef close
28 #undef signal
29
30 #include <stdio.h>
31 #include <getopt.h>
32
33 char *getenv (), *getwd ();
34 char *getcwd ();
35 int geteuid ();
36
37 /* This is defined with -D from the compilation command,
38 which extracts it from ../lisp/version.el. */
39
40 #ifndef VERSION
41 #define VERSION "unspecified"
42 #endif
43 \f
44 /* Name used to invoke this program. */
45 char *progname;
46
47 /* Nonzero means don't wait for a response from Emacs. --nowait. */
48 int nowait = 0;
49
50 struct option longopts[] =
51 {
52 { "nowait", no_argument, NULL, 'n' },
53 { "help", no_argument, NULL, 'H' },
54 { "version", no_argument, NULL, 'V' },
55 { 0 }
56 };
57
58 /* Decode the options from argv and argc.
59 The global variable `optind' will say how many arguments we used up. */
60
61 void
62 decode_options (argc, argv)
63 int argc;
64 char **argv;
65 {
66 while (1)
67 {
68 int opt = getopt_long (argc, argv,
69 "VHn", longopts, 0);
70
71 if (opt == EOF)
72 break;
73
74 switch (opt)
75 {
76 case 0:
77 /* If getopt returns 0, then it has already processed a
78 long-named option. We should do nothing. */
79 break;
80
81 case 'n':
82 nowait = 1;
83 break;
84
85 case 'V':
86 fprintf (stderr, "Version %s\n", VERSION);
87 exit (1);
88 break;
89
90 case 'H':
91 default:
92 print_help_and_exit ();
93 }
94 }
95 }
96
97 print_help_and_exit ()
98 {
99 fprintf (stderr,
100 "Usage: %s [-n] [--nowait] [+linenumber] filename\n",
101 progname);
102 fprintf (stderr,
103 "Report bugs to bug-gnu-emacs@prep.ai.mit.edu.\n");
104 exit (1);
105 }
106
107 /* Return a copy of NAME, inserting a \
108 before each \, each -, and each space.
109 Change spaces to underscores, too, so that the
110 return value never contains a space. */
111
112 char *
113 quote_file_name (name)
114 char *name;
115 {
116 char *copy = (char *) malloc (strlen (name) * 2 + 1);
117 char *p, *q;
118
119 p = name;
120 q = copy;
121 while (*p)
122 {
123 if (*p == ' ')
124 {
125 *q++ = '\\';
126 *q++ = '_';
127 p++;
128 }
129 else
130 {
131 if (*p == '\\' || *p == '-')
132 *q++ = '\\';
133 *q++ = *p++;
134 }
135 }
136
137 return copy;
138 }
139 \f
140 #if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC)
141
142 main (argc, argv)
143 int argc;
144 char **argv;
145 {
146 fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
147 argv[0]);
148 fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n");
149 exit (1);
150 }
151
152 #else /* HAVE_SOCKETS or HAVE_SYSVIPC */
153
154 #if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM)
155 /* BSD code is very different from SYSV IPC code */
156
157 #include <sys/types.h>
158 #include <sys/socket.h>
159 #include <sys/un.h>
160 #include <sys/stat.h>
161 #include <errno.h>
162
163 extern char *strerror ();
164 extern int errno;
165
166 int
167 main (argc, argv)
168 int argc;
169 char **argv;
170 {
171 char system_name[32];
172 int s, i;
173 FILE *out, *in;
174 struct sockaddr_un server;
175 char *homedir, *cwd, *str;
176 char string[BUFSIZ];
177
178 progname = argv[0];
179
180 /* Process options. */
181 decode_options (argc, argv);
182
183 if (argc - optind < 1)
184 print_help_and_exit ();
185
186 /*
187 * Open up an AF_UNIX socket in this person's home directory
188 */
189
190 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
191 {
192 fprintf (stderr, "%s: ", argv[0]);
193 perror ("socket");
194 exit (1);
195 }
196 server.sun_family = AF_UNIX;
197 #ifndef SERVER_HOME_DIR
198 {
199 struct stat statbfr;
200
201 gethostname (system_name, sizeof (system_name));
202 sprintf (server.sun_path, "/tmp/esrv%d-%s", geteuid (), system_name);
203
204 if (stat (server.sun_path, &statbfr) == -1)
205 {
206 if (errno == ENOENT)
207 fprintf (stderr,
208 "%s: can't find socket; have you started the server?\n",
209 argv[0]);
210 else
211 fprintf (stderr, "%s: can't stat %s: %s\n",
212 argv[0], server.sun_path, strerror (errno));
213 exit (1);
214 }
215 if (statbfr.st_uid != geteuid ())
216 {
217 fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
218 exit (1);
219 }
220 }
221 #else
222 if ((homedir = getenv ("HOME")) == NULL)
223 {
224 fprintf (stderr, "%s: No home directory\n", argv[0]);
225 exit (1);
226 }
227 strcpy (server.sun_path, homedir);
228 strcat (server.sun_path, "/.emacs-server-");
229 gethostname (system_name, sizeof (system_name));
230 strcat (server.sun_path, system_name);
231 #endif
232
233 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
234 < 0)
235 {
236 fprintf (stderr, "%s: ", argv[0]);
237 perror ("connect");
238 exit (1);
239 }
240
241 /* We use the stream OUT to send our command to the server. */
242 if ((out = fdopen (s, "r+")) == NULL)
243 {
244 fprintf (stderr, "%s: ", argv[0]);
245 perror ("fdopen");
246 exit (1);
247 }
248
249 /* We use the stream IN to read the response.
250 We used to use just one stream for both output and input
251 on the socket, but reversing direction works nonportably:
252 on some systems, the output appears as the first input;
253 on other systems it does not. */
254 if ((in = fdopen (s, "r+")) == NULL)
255 {
256 fprintf (stderr, "%s: ", argv[0]);
257 perror ("fdopen");
258 exit (1);
259 }
260
261 #ifdef BSD
262 cwd = getwd (string);
263 #else
264 cwd = getcwd (string, sizeof string);
265 #endif
266 if (cwd == 0)
267 {
268 /* getwd puts message in STRING if it fails. */
269 fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
270 exit (1);
271 }
272
273 if (nowait)
274 fprintf (out, "-nowait ");
275
276 for (i = optind; i < argc; i++)
277 {
278 if (*argv[i] == '+')
279 {
280 char *p = argv[i] + 1;
281 while (*p >= '0' && *p <= '9') p++;
282 if (*p != 0)
283 fprintf (out, "%s/", cwd);
284 }
285 else if (*argv[i] != '/')
286 fprintf (out, "%s/", cwd);
287
288 fprintf (out, "%s ", quote_file_name (argv[i]));
289 }
290 fprintf (out, "\n");
291 fflush (out);
292
293 /* Maybe wait for an answer. */
294 if (nowait)
295 return 0;
296
297 printf ("Waiting for Emacs...");
298 fflush (stdout);
299
300 /* Now, wait for an answer and print any messages. On some systems,
301 the first line we read will actually be the output we just sent.
302 We can't predict whether that will happen, so if it does, we
303 detect it by recognizing `Client: ' at the beginning. */
304
305 while (str = fgets (string, BUFSIZ, in))
306 printf ("%s", str);
307
308 return 0;
309 }
310
311 #else /* This is the SYSV IPC section */
312
313 #include <sys/types.h>
314 #include <sys/ipc.h>
315 #include <sys/msg.h>
316 #include <sys/utsname.h>
317 #include <stdio.h>
318
319 char *getwd (), *getcwd (), *getenv ();
320 struct utsname system_name;
321
322 main (argc, argv)
323 int argc;
324 char **argv;
325 {
326 int s;
327 key_t key;
328 /* Size of text allocated in MSGP. */
329 int size_allocated = BUFSIZ;
330 /* Amount of text used in MSGP. */
331 int used;
332 struct msgbuf *msgp
333 = (struct msgbuf *) malloc (sizeof (struct msgbuf) + size_allocated);
334 struct msqid_ds * msg_st;
335 char *homedir, buf[BUFSIZ];
336 char gwdirb[BUFSIZ];
337 char *cwd;
338 char *temp;
339
340 progname = argv[0];
341
342 /* Process options. */
343 decode_options (argc, argv);
344
345 if (argc - optind < 1)
346 print_help_and_exit ();
347
348 /*
349 * Create a message queue using ~/.emacs-server as the path for ftok
350 */
351 if ((homedir = getenv ("HOME")) == NULL)
352 {
353 fprintf (stderr, "%s: No home directory\n", argv[0]);
354 exit (1);
355 }
356 strcpy (buf, homedir);
357 #ifndef HAVE_LONG_FILE_NAMES
358 /* If file names are short, we can't fit the host name. */
359 strcat (buf, "/.emacs-server");
360 #else
361 strcat (buf, "/.emacs-server-");
362 uname (&system_name);
363 strcat (buf, system_name.nodename);
364 #endif
365 creat (buf, 0600);
366 key = ftok (buf, 1); /* unlikely to be anyone else using it */
367 s = msgget (key, 0600 | IPC_CREAT);
368 if (s == -1)
369 {
370 fprintf (stderr, "%s: ", argv[0]);
371 perror ("msgget");
372 exit (1);
373 }
374
375 /* Determine working dir, so we can prefix it to all the arguments. */
376 #ifdef BSD
377 temp = getwd (gwdirb);
378 #else
379 temp = getcwd (gwdirb, sizeof gwdirb);
380 #endif
381
382 cwd = gwdirb;
383 if (temp != 0)
384 {
385 /* On some systems, cwd can look like `@machine/...';
386 ignore everything before the first slash in such a case. */
387 while (*cwd && *cwd != '/')
388 cwd++;
389 strcat (cwd, "/");
390 }
391 else
392 {
393 fprintf (stderr, "%s: %s\n", argv[0], cwd);
394 exit (1);
395 }
396
397 msgp->mtext[0] = 0;
398 used = 0;
399
400 if (nowait)
401 {
402 strcat (msgp->mtext, "-nowait ");
403 used += 8;
404 }
405
406 argc -= optind;
407 argv += optind;
408
409 while (argc)
410 {
411 int need_cwd = 0;
412 char *modified_arg = argv[0];
413
414 if (*modified_arg == '+')
415 {
416 char *p = modified_arg + 1;
417 while (*p >= '0' && *p <= '9') p++;
418 if (*p != 0)
419 need_cwd = 1;
420 }
421 else if (*modified_arg != '/')
422 need_cwd = 1;
423
424 modified_arg = quote_file_name (modified_arg);
425
426 if (need_cwd)
427 used += strlen (cwd);
428 used += strlen (modified_arg) + 1;
429 while (used + 2 > size_allocated)
430 {
431 size_allocated *= 2;
432 msgp = (struct msgbuf *) realloc (msgp,
433 (sizeof (struct msgbuf)
434 + size_allocated));
435 }
436
437 if (need_cwd)
438 strcat (msgp->mtext, cwd);
439
440 strcat (msgp->mtext, modified_arg);
441 strcat (msgp->mtext, " ");
442 argv++; argc--;
443 }
444 strcat (msgp->mtext, "\n");
445 #ifdef HPUX /* HPUX has a bug. */
446 if (strlen (msgp->mtext) >= 512)
447 {
448 fprintf (stderr, "%s: args too long for msgsnd\n", progname);
449 exit (1);
450 }
451 #endif
452 msgp->mtype = 1;
453 if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
454 {
455 fprintf (stderr, "%s: ", progname);
456 perror ("msgsnd");
457 exit (1);
458 }
459
460 /* Maybe wait for an answer. */
461 if (nowait)
462 return 0;
463
464 printf ("Waiting for Emacs...");
465 fflush (stdout);
466
467 msgrcv (s, msgp, BUFSIZ, getpid (), 0); /* wait for anything back */
468 strcpy (buf, msgp->mtext);
469
470 printf ("\n");
471 if (*buf)
472 printf ("%s\n", buf);
473 exit (0);
474 }
475
476 #endif /* HAVE_SYSVIPC */
477
478 #endif /* HAVE_SOCKETS or HAVE_SYSVIPC */
479 \f
480 #ifndef HAVE_STRERROR
481 char *
482 strerror (errnum)
483 int errnum;
484 {
485 extern char *sys_errlist[];
486 extern int sys_nerr;
487
488 if (errnum >= 0 && errnum < sys_nerr)
489 return sys_errlist[errnum];
490 return (char *) "Unknown error";
491 }
492
493 #endif /* ! HAVE_STRERROR */