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