Include <config.h>.
[bpt/emacs.git] / lib-src / emacsclient.c
1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22
23 #define NO_SHORTNAMES
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #undef signal
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <getopt.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #ifdef VMS
39 # include "vms-pwd.h"
40 #else
41 # include <pwd.h>
42 #endif /* not VMS */
43
44 char *getenv (), *getwd ();
45 char *getcwd ();
46
47 /* This is defined with -D from the compilation command,
48 which extracts it from ../lisp/version.el. */
49
50 #ifndef VERSION
51 #define VERSION "unspecified"
52 #endif
53 \f
54 /* Name used to invoke this program. */
55 char *progname;
56
57 /* Nonzero means don't wait for a response from Emacs. --no-wait. */
58 int nowait = 0;
59
60 void print_help_and_exit ();
61
62 struct option longopts[] =
63 {
64 { "no-wait", no_argument, NULL, 'n' },
65 { "help", no_argument, NULL, 'H' },
66 { "version", no_argument, NULL, 'V' },
67 { "alternate-editor",required_argument, NULL, 'a' },
68 { 0 }
69 };
70
71
72 const char * alternate_editor = NULL;
73
74 /* Decode the options from argv and argc.
75 The global variable `optind' will say how many arguments we used up. */
76
77 void
78 decode_options (argc, argv)
79 int argc;
80 char **argv;
81 {
82 while (1)
83 {
84 int opt = getopt_long (argc, argv,
85 "VHna:", longopts, 0);
86
87 if (opt == EOF)
88 break;
89
90 alternate_editor = getenv ("ALTERNATE_EDITOR");
91
92 switch (opt)
93 {
94 case 0:
95 /* If getopt returns 0, then it has already processed a
96 long-named option. We should do nothing. */
97 break;
98
99 case 'a':
100 alternate_editor = optarg;
101 break;
102
103 case 'n':
104 nowait = 1;
105 break;
106
107 case 'V':
108 fprintf (stderr, "emacsclient %s\n", VERSION);
109 exit (1);
110 break;
111
112 case 'H':
113 default:
114 print_help_and_exit ();
115 }
116 }
117 }
118
119 void
120 print_help_and_exit ()
121 {
122 fprintf (stderr,
123 "Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINE[:COLUMN]] FILENAME\n",
124 progname);
125 fprintf (stderr,
126 "Or %s --version\n",
127 progname);
128 fprintf (stderr,
129 "Report bugs to bug-gnu-emacs@gnu.org.\n");
130 exit (1);
131 }
132
133 /* Return a copy of NAME, inserting a &
134 before each &, each space, and any initial -.
135 Change spaces to underscores, too, so that the
136 return value never contains a space. */
137
138 char *
139 quote_file_name (name)
140 char *name;
141 {
142 char *copy = (char *) malloc (strlen (name) * 2 + 1);
143 char *p, *q;
144
145 p = name;
146 q = copy;
147 while (*p)
148 {
149 if (*p == ' ')
150 {
151 *q++ = '&';
152 *q++ = '_';
153 p++;
154 }
155 else
156 {
157 if (*p == '&' || (*p == '-' && p == name))
158 *q++ = '&';
159 *q++ = *p++;
160 }
161 }
162 *q++ = 0;
163
164 return copy;
165 }
166
167 /* Like malloc but get fatal error if memory is exhausted. */
168
169 long *
170 xmalloc (size)
171 unsigned int size;
172 {
173 long *result = (long *) malloc (size);
174 if (result == NULL)
175 {
176 perror ("malloc");
177 exit (1);
178 }
179 return result;
180 }
181 \f
182 /*
183 Try to run a different command, or --if no alternate editor is
184 defined-- exit with an errorcode.
185 */
186 void
187 fail (argc, argv)
188 int argc;
189 char **argv;
190 {
191 if (alternate_editor)
192 {
193 int i = optind -1 ;
194 execvp (alternate_editor, argv + i);
195 return;
196 }
197 else
198 {
199 exit (1);
200 }
201 }
202
203
204 \f
205 #if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC)
206
207 int
208 main (argc, argv)
209 int argc;
210 char **argv;
211 {
212 fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
213 argv[0]);
214 fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n");
215
216 fail (argc, argv);
217 }
218
219 #else /* HAVE_SOCKETS or HAVE_SYSVIPC */
220
221 #if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM)
222 /* BSD code is very different from SYSV IPC code */
223
224 #include <sys/types.h>
225 #include <sys/socket.h>
226 #include <sys/un.h>
227 #include <sys/stat.h>
228 #include <errno.h>
229
230 extern char *strerror ();
231 extern int errno;
232
233 /* Three possibilities:
234 2 - can't be `stat'ed (sets errno)
235 1 - isn't owned by us
236 0 - success: none of the above */
237
238 static int
239 socket_status (socket_name)
240 char *socket_name;
241 {
242 struct stat statbfr;
243
244 if (stat (socket_name, &statbfr) == -1)
245 return 2;
246
247 if (statbfr.st_uid != geteuid ())
248 return 1;
249
250 return 0;
251 }
252
253 int
254 main (argc, argv)
255 int argc;
256 char **argv;
257 {
258 char *system_name;
259 int system_name_length;
260 int s, i;
261 FILE *out, *in;
262 struct sockaddr_un server;
263 #ifdef SERVER_HOME_DIR
264 char *homedir;
265 #endif
266 char *cwd, *str;
267 char string[BUFSIZ];
268
269 progname = argv[0];
270
271 /* Process options. */
272 decode_options (argc, argv);
273
274 if (argc - optind < 1)
275 print_help_and_exit ();
276
277 /*
278 * Open up an AF_UNIX socket in this person's home directory
279 */
280
281 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
282 {
283 fprintf (stderr, "%s: ", argv[0]);
284 perror ("socket");
285 fail (argc, argv);
286 }
287
288 server.sun_family = AF_UNIX;
289
290 {
291 system_name_length = 32;
292
293 while (1)
294 {
295 system_name = (char *) xmalloc (system_name_length + 1);
296
297 /* system_name must be null-terminated string. */
298 system_name[system_name_length] = '\0';
299
300 if (gethostname (system_name, system_name_length) == 0)
301 break;
302
303 free (system_name);
304 system_name_length *= 2;
305 }
306 }
307
308 #ifndef SERVER_HOME_DIR
309 {
310 int sock_status = 0;
311
312 sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name);
313
314 /* See if the socket exists, and if it's owned by us. */
315 sock_status = socket_status (server.sun_path);
316 if (sock_status)
317 {
318 /* Failing that, see if LOGNAME or USER exist and differ from
319 our euid. If so, look for a socket based on the UID
320 associated with the name. This is reminiscent of the logic
321 that init_editfns uses to set the global Vuser_full_name. */
322
323 char *user_name = (char *) getenv ("LOGNAME");
324 if (!user_name)
325 user_name = (char *) getenv ("USER");
326
327 if (user_name)
328 {
329 struct passwd *pw = getpwnam (user_name);
330 if (pw && (pw->pw_uid != geteuid ()))
331 {
332 /* We're running under su, apparently. */
333 sprintf (server.sun_path, "/tmp/esrv%d-%s",
334 (int) pw->pw_uid, system_name);
335 sock_status = socket_status (server.sun_path);
336 }
337 }
338 }
339
340 switch (sock_status)
341 {
342 case 1:
343 /* There's a socket, but it isn't owned by us. This is OK if
344 we are root. */
345 if (0 != geteuid ())
346 {
347 fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
348 fail (argc, argv);
349 }
350 break;
351
352 case 2:
353 /* `stat' failed */
354 if (errno == ENOENT)
355 fprintf (stderr,
356 "%s: can't find socket; have you started the server?\n",
357 argv[0]);
358 else
359 fprintf (stderr, "%s: can't stat %s: %s\n",
360 argv[0], server.sun_path, strerror (errno));
361 fail (argc, argv);
362 break;
363 }
364 }
365 #else
366 if ((homedir = getenv ("HOME")) == NULL)
367 {
368 fprintf (stderr, "%s: No home directory\n", argv[0]);
369 fail (argc, argv);
370 }
371 strcpy (server.sun_path, homedir);
372 strcat (server.sun_path, "/.emacs-server-");
373 strcat (server.sun_path, system_name);
374 #endif
375
376 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
377 < 0)
378 {
379 fprintf (stderr, "%s: ", argv[0]);
380 perror ("connect");
381 fail (argc, argv);
382 }
383
384 /* We use the stream OUT to send our command to the server. */
385 if ((out = fdopen (s, "r+")) == NULL)
386 {
387 fprintf (stderr, "%s: ", argv[0]);
388 perror ("fdopen");
389 fail (argc, argv);
390 }
391
392 /* We use the stream IN to read the response.
393 We used to use just one stream for both output and input
394 on the socket, but reversing direction works nonportably:
395 on some systems, the output appears as the first input;
396 on other systems it does not. */
397 if ((in = fdopen (s, "r+")) == NULL)
398 {
399 fprintf (stderr, "%s: ", argv[0]);
400 perror ("fdopen");
401 fail (argc, argv);
402 }
403
404 #ifdef BSD_SYSTEM
405 cwd = getwd (string);
406 #else
407 cwd = getcwd (string, sizeof string);
408 #endif
409 if (cwd == 0)
410 {
411 /* getwd puts message in STRING if it fails. */
412 fprintf (stderr, "%s: %s (%s)\n", argv[0],
413 #ifdef BSD_SYSTEM
414 string,
415 #else
416 "Cannot get current working directory",
417 #endif
418 strerror (errno));
419 fail (argc, argv);
420 }
421
422 if (nowait)
423 fprintf (out, "-nowait ");
424
425 for (i = optind; i < argc; i++)
426 {
427 if (*argv[i] == '+')
428 {
429 char *p = argv[i] + 1;
430 while (isdigit ((unsigned char) *p) || *p == ':') p++;
431 if (*p != 0)
432 fprintf (out, "%s/", quote_file_name (cwd));
433 }
434 else if (*argv[i] != '/')
435 fprintf (out, "%s/", quote_file_name (cwd));
436
437 fprintf (out, "%s ", quote_file_name (argv[i]));
438 }
439 fprintf (out, "\n");
440 fflush (out);
441
442 /* Maybe wait for an answer. */
443 if (nowait)
444 return 0;
445
446 printf ("Waiting for Emacs...");
447 fflush (stdout);
448
449 /* Now, wait for an answer and print any messages. On some systems,
450 the first line we read will actually be the output we just sent.
451 We can't predict whether that will happen, so if it does, we
452 detect it by recognizing `Client: ' at the beginning. */
453
454 while ((str = fgets (string, BUFSIZ, in)))
455 printf ("%s", str);
456
457 return 0;
458 }
459
460 #else /* This is the SYSV IPC section */
461
462 #include <sys/types.h>
463 #include <sys/ipc.h>
464 #include <sys/msg.h>
465 #include <sys/utsname.h>
466 #include <stdio.h>
467 #include <errno.h>
468 extern int errno;
469
470 char *getwd (), *getcwd (), *getenv ();
471 struct utsname system_name;
472
473 main (argc, argv)
474 int argc;
475 char **argv;
476 {
477 int s;
478 key_t key;
479 /* Size of text allocated in MSGP. */
480 int size_allocated = BUFSIZ;
481 /* Amount of text used in MSGP. */
482 int used;
483 struct msgbuf *msgp
484 = (struct msgbuf *) malloc (sizeof (struct msgbuf) + size_allocated);
485 struct msqid_ds * msg_st;
486 char *homedir, buf[BUFSIZ];
487 char gwdirb[BUFSIZ];
488 char *cwd;
489 char *temp;
490
491 progname = argv[0];
492
493 /* Process options. */
494 decode_options (argc, argv);
495
496 if (argc - optind < 1)
497 print_help_and_exit ();
498
499 /*
500 * Create a message queue using ~/.emacs-server as the path for ftok
501 */
502 if ((homedir = getenv ("HOME")) == NULL)
503 {
504 fprintf (stderr, "%s: No home directory\n", argv[0]);
505 exit (1);
506 }
507 strcpy (buf, homedir);
508 #ifndef HAVE_LONG_FILE_NAMES
509 /* If file names are short, we can't fit the host name. */
510 strcat (buf, "/.emacs-server");
511 #else
512 strcat (buf, "/.emacs-server-");
513 uname (&system_name);
514 strcat (buf, system_name.nodename);
515 #endif
516 creat (buf, 0600);
517 key = ftok (buf, 1); /* unlikely to be anyone else using it */
518 s = msgget (key, 0600 | IPC_CREAT);
519 if (s == -1)
520 {
521 fprintf (stderr, "%s: ", argv[0]);
522 perror ("msgget");
523 exit (1);
524 }
525
526 /* Determine working dir, so we can prefix it to all the arguments. */
527 #ifdef BSD_SYSTEM
528 temp = getwd (gwdirb);
529 #else
530 temp = getcwd (gwdirb, sizeof gwdirb);
531 #endif
532
533 cwd = gwdirb;
534 if (temp != 0)
535 {
536 /* On some systems, cwd can look like `@machine/...';
537 ignore everything before the first slash in such a case. */
538 while (*cwd && *cwd != '/')
539 cwd++;
540 strcat (cwd, "/");
541 }
542 else
543 {
544 #ifdef BSD_SYSTEM
545 fprintf (stderr, "%s: %s\n", argv[0], cwd);
546 #else
547 fprintf (stderr, "%s: Cannot get current working directory: %s\n",
548 argv[0], strerror (errno));
549 #endif
550 fail (argc, argv);
551 }
552
553 msgp->mtext[0] = 0;
554 used = 0;
555
556 if (nowait)
557 {
558 strcat (msgp->mtext, "-nowait ");
559 used += 8;
560 }
561
562 argc -= optind;
563 argv += optind;
564
565 while (argc)
566 {
567 int need_cwd = 0;
568 char *modified_arg = argv[0];
569
570 if (*modified_arg == '+')
571 {
572 char *p = modified_arg + 1;
573 while (isdigit (*p) || *p == ':')
574 p++;
575 if (*p != 0)
576 need_cwd = 1;
577 }
578 else if (*modified_arg != '/')
579 need_cwd = 1;
580
581 modified_arg = quote_file_name (modified_arg);
582
583 if (need_cwd)
584 /* Overestimate in case we have to quote something in CWD. */
585 used += 2 * strlen (cwd);
586 used += strlen (modified_arg) + 1;
587 while (used + 2 > size_allocated)
588 {
589 size_allocated *= 2;
590 msgp = (struct msgbuf *) realloc (msgp,
591 (sizeof (struct msgbuf)
592 + size_allocated));
593 }
594
595 if (need_cwd)
596 strcat (msgp->mtext, quote_file_name (cwd));
597
598 strcat (msgp->mtext, modified_arg);
599 strcat (msgp->mtext, " ");
600 argv++; argc--;
601 }
602 strcat (msgp->mtext, "\n");
603 #ifdef HPUX /* HPUX has a bug. */
604 if (strlen (msgp->mtext) >= 512)
605 {
606 fprintf (stderr, "%s: args too long for msgsnd\n", progname);
607 fail (argc, argv);
608 }
609 #endif
610 msgp->mtype = 1;
611 if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
612 {
613 fprintf (stderr, "%s: ", progname);
614 perror ("msgsnd");
615 fail (argc, argv);
616 }
617
618 /* Maybe wait for an answer. */
619 if (nowait)
620 return 0;
621
622 printf ("Waiting for Emacs...");
623 fflush (stdout);
624
625 msgrcv (s, msgp, BUFSIZ, getpid (), 0); /* wait for anything back */
626 strcpy (buf, msgp->mtext);
627
628 printf ("\n");
629 if (*buf)
630 printf ("%s\n", buf);
631 exit (0);
632 }
633
634 #endif /* HAVE_SYSVIPC */
635
636 #endif /* HAVE_SOCKETS or HAVE_SYSVIPC */
637 \f
638 #ifndef HAVE_STRERROR
639 char *
640 strerror (errnum)
641 int errnum;
642 {
643 extern char *sys_errlist[];
644 extern int sys_nerr;
645
646 if (errnum >= 0 && errnum < sys_nerr)
647 return sys_errlist[errnum];
648 return (char *) "Unknown error";
649 }
650
651 #endif /* ! HAVE_STRERROR */