(customize-face-other-window, customize-face):
[bpt/emacs.git] / lib-src / emacsclient.c
CommitLineData
efb859b4 1/* Client process that communicates with GNU Emacs acting as server.
de073ce3
GM
2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001
3 Free Software Foundation, Inc.
46cec291
RS
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
92af894f 9the Free Software Foundation; either version 2, or (at your option)
46cec291
RS
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
46cec291
RS
21
22
23#define NO_SHORTNAMES
e69233c2
PJ
24
25#ifdef HAVE_CONFIG_H
2f8fe2f4 26#include <config.h>
e69233c2
PJ
27#endif
28
4e23f2ba 29#undef signal
46cec291 30
e69233c2 31#include <ctype.h>
8f9aaa0a
RS
32#include <stdio.h>
33#include <getopt.h>
79f13bba
DL
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
8f9aaa0a 37
9f637eea
GM
38#ifdef VMS
39# include "vms-pwd.h"
40#else
41# include <pwd.h>
42#endif /* not VMS */
43
8f9aaa0a
RS
44char *getenv (), *getwd ();
45char *getcwd ();
8f9aaa0a
RS
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. */
55char *progname;
56
749ae770 57/* Nonzero means don't wait for a response from Emacs. --no-wait. */
8f9aaa0a
RS
58int nowait = 0;
59
7f3bff3e
AS
60void print_help_and_exit ();
61
8f9aaa0a
RS
62struct option longopts[] =
63{
749ae770 64 { "no-wait", no_argument, NULL, 'n' },
8f9aaa0a
RS
65 { "help", no_argument, NULL, 'H' },
66 { "version", no_argument, NULL, 'V' },
97e3214d 67 { "alternate-editor",required_argument, NULL, 'a' },
8f9aaa0a
RS
68 { 0 }
69};
70
97e3214d
GM
71
72const char * alternate_editor = NULL;
73
8f9aaa0a 74/* Decode the options from argv and argc.
5212210c 75 The global variable `optind' will say how many arguments we used up. */
8f9aaa0a 76
5212210c 77void
8f9aaa0a
RS
78decode_options (argc, argv)
79 int argc;
80 char **argv;
81{
82 while (1)
83 {
84 int opt = getopt_long (argc, argv,
97e3214d 85 "VHna:", longopts, 0);
8f9aaa0a
RS
86
87 if (opt == EOF)
88 break;
89
97e3214d 90 alternate_editor = getenv ("ALTERNATE_EDITOR");
e69233c2 91
8f9aaa0a
RS
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;
e69233c2 98
97e3214d
GM
99 case 'a':
100 alternate_editor = optarg;
101 break;
e69233c2 102
8f9aaa0a
RS
103 case 'n':
104 nowait = 1;
105 break;
106
107 case 'V':
b4e94f42 108 fprintf (stderr, "emacsclient %s\n", VERSION);
8f9aaa0a
RS
109 exit (1);
110 break;
46cec291 111
8f9aaa0a
RS
112 case 'H':
113 default:
114 print_help_and_exit ();
115 }
116 }
8f9aaa0a
RS
117}
118
7f3bff3e 119void
8f9aaa0a
RS
120print_help_and_exit ()
121{
122 fprintf (stderr,
8b8f50f8 123 "Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINE[:COLUMN]] FILENAME\n",
8f9aaa0a 124 progname);
4852ed0e
RS
125 fprintf (stderr,
126 "Or %s --version\n",
127 progname);
8f9aaa0a 128 fprintf (stderr,
b4e94f42 129 "Report bugs to bug-gnu-emacs@gnu.org.\n");
8f9aaa0a
RS
130 exit (1);
131}
5212210c 132
f1db6a73
RS
133/* Return a copy of NAME, inserting a &
134 before each &, each space, and any initial -.
5212210c
RS
135 Change spaces to underscores, too, so that the
136 return value never contains a space. */
137
138char *
139quote_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 {
f1db6a73 151 *q++ = '&';
5212210c
RS
152 *q++ = '_';
153 p++;
154 }
155 else
156 {
f1db6a73
RS
157 if (*p == '&' || (*p == '-' && p == name))
158 *q++ = '&';
5212210c
RS
159 *q++ = *p++;
160 }
161 }
f1db6a73 162 *q++ = 0;
5212210c
RS
163
164 return copy;
165}
0c76956f 166
0c76956f
RS
167/* Like malloc but get fatal error if memory is exhausted. */
168
5497dfdb 169long *
0c76956f
RS
170xmalloc (size)
171 unsigned int size;
172{
5f32a712 173 long *result = (long *) malloc (size);
0c76956f
RS
174 if (result == NULL)
175 {
176 perror ("malloc");
177 exit (1);
178 }
179 return result;
180}
8f9aaa0a 181\f
97e3214d
GM
182/*
183 Try to run a different command, or --if no alternate editor is
184 defined-- exit with an errorcode.
185*/
de073ce3 186void
97e3214d
GM
187fail (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);
23431241 195 return;
97e3214d
GM
196 }
197 else
198 {
199 exit (1);
200 }
201}
202
203
97e3214d 204\f
b135a7cf 205#if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC)
46cec291 206
de073ce3 207int
46cec291
RS
208main (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");
97e3214d
GM
215
216 fail (argc, argv);
46cec291
RS
217}
218
219#else /* HAVE_SOCKETS or HAVE_SYSVIPC */
220
1e523e3d 221#if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM)
46cec291
RS
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>
efb859b4 227#include <sys/stat.h>
46cec291
RS
228#include <errno.h>
229
92af894f 230extern char *strerror ();
46cec291
RS
231extern int errno;
232
9f637eea
GM
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
238static int
239socket_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
340ff9de 253int
46cec291
RS
254main (argc, argv)
255 int argc;
256 char **argv;
257{
a2b3f2b5
RS
258 char *system_name;
259 int system_name_length;
46cec291 260 int s, i;
23a7488d 261 FILE *out, *in;
46cec291 262 struct sockaddr_un server;
571512de
EZ
263#ifdef SERVER_HOME_DIR
264 char *homedir;
265#endif
266 char *cwd, *str;
46cec291 267 char string[BUFSIZ];
8f9aaa0a
RS
268
269 progname = argv[0];
46cec291 270
8f9aaa0a 271 /* Process options. */
5212210c 272 decode_options (argc, argv);
46cec291 273
5212210c 274 if (argc - optind < 1)
8f9aaa0a 275 print_help_and_exit ();
46cec291 276
e69233c2 277 /*
46cec291
RS
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");
97e3214d 285 fail (argc, argv);
46cec291 286 }
e69233c2 287
46cec291 288 server.sun_family = AF_UNIX;
c5fee545 289
efb859b4 290 {
a2b3f2b5
RS
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 }
c5fee545
KH
306 }
307
308#ifndef SERVER_HOME_DIR
309 {
9f637eea 310 int sock_status = 0;
efb859b4 311
23431241 312 sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name);
efb859b4 313
9f637eea
GM
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)
efb859b4 317 {
9f637eea
GM
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. */
e69233c2 322
9f637eea
GM
323 char *user_name = (char *) getenv ("LOGNAME");
324 if (!user_name)
325 user_name = (char *) getenv ("USER");
e69233c2 326
9f637eea
GM
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",
23431241 334 (int) pw->pw_uid, system_name);
9f637eea
GM
335 sock_status = socket_status (server.sun_path);
336 }
337 }
efb859b4 338 }
e69233c2 339
9f637eea
GM
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;
e69233c2 351
9f637eea
GM
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 }
efb859b4 364 }
46cec291
RS
365#else
366 if ((homedir = getenv ("HOME")) == NULL)
367 {
368 fprintf (stderr, "%s: No home directory\n", argv[0]);
97e3214d 369 fail (argc, argv);
46cec291
RS
370 }
371 strcpy (server.sun_path, homedir);
b135a7cf 372 strcat (server.sun_path, "/.emacs-server-");
b135a7cf 373 strcat (server.sun_path, system_name);
46cec291
RS
374#endif
375
4e23f2ba
JB
376 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
377 < 0)
46cec291
RS
378 {
379 fprintf (stderr, "%s: ", argv[0]);
380 perror ("connect");
97e3214d 381 fail (argc, argv);
46cec291 382 }
23a7488d
RS
383
384 /* We use the stream OUT to send our command to the server. */
46cec291
RS
385 if ((out = fdopen (s, "r+")) == NULL)
386 {
387 fprintf (stderr, "%s: ", argv[0]);
388 perror ("fdopen");
97e3214d 389 fail (argc, argv);
46cec291
RS
390 }
391
23a7488d
RS
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");
97e3214d 401 fail (argc, argv);
23a7488d
RS
402 }
403
e397a017 404#ifdef BSD_SYSTEM
46cec291 405 cwd = getwd (string);
ee6a193c
RS
406#else
407 cwd = getcwd (string, sizeof string);
408#endif
46cec291
RS
409 if (cwd == 0)
410 {
411 /* getwd puts message in STRING if it fails. */
bd252662
RS
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));
97e3214d 419 fail (argc, argv);
46cec291
RS
420 }
421
5212210c
RS
422 if (nowait)
423 fprintf (out, "-nowait ");
292d74a3 424
5212210c
RS
425 for (i = optind; i < argc; i++)
426 {
46cec291
RS
427 if (*argv[i] == '+')
428 {
429 char *p = argv[i] + 1;
cb1cdedd 430 while (isdigit ((unsigned char) *p) || *p == ':') p++;
46cec291 431 if (*p != 0)
0343a017 432 fprintf (out, "%s/", quote_file_name (cwd));
46cec291
RS
433 }
434 else if (*argv[i] != '/')
0343a017 435 fprintf (out, "%s/", quote_file_name (cwd));
5212210c
RS
436
437 fprintf (out, "%s ", quote_file_name (argv[i]));
46cec291
RS
438 }
439 fprintf (out, "\n");
440 fflush (out);
441
292d74a3
RS
442 /* Maybe wait for an answer. */
443 if (nowait)
444 return 0;
445
46cec291
RS
446 printf ("Waiting for Emacs...");
447 fflush (stdout);
448
23a7488d
RS
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. */
e69233c2
PJ
453
454 while ((str = fgets (string, BUFSIZ, in)))
46cec291 455 printf ("%s", str);
23a7488d 456
340ff9de 457 return 0;
46cec291
RS
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>
b135a7cf 465#include <sys/utsname.h>
46cec291 466#include <stdio.h>
bd252662
RS
467#include <errno.h>
468extern int errno;
46cec291 469
1518a9eb 470char *getwd (), *getcwd (), *getenv ();
b135a7cf 471struct utsname system_name;
1518a9eb 472
46cec291
RS
473main (argc, argv)
474 int argc;
475 char **argv;
476{
477 int s;
478 key_t key;
1518a9eb
RS
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);
46cec291
RS
485 struct msqid_ds * msg_st;
486 char *homedir, buf[BUFSIZ];
487 char gwdirb[BUFSIZ];
488 char *cwd;
489 char *temp;
8f9aaa0a
RS
490
491 progname = argv[0];
492
493 /* Process options. */
5212210c 494 decode_options (argc, argv);
46cec291 495
5212210c 496 if (argc - optind < 1)
8f9aaa0a 497 print_help_and_exit ();
46cec291
RS
498
499 /*
b135a7cf 500 * Create a message queue using ~/.emacs-server as the path for ftok
46cec291
RS
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);
b135a7cf
RS
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
46cec291
RS
516 creat (buf, 0600);
517 key = ftok (buf, 1); /* unlikely to be anyone else using it */
61a93162 518 s = msgget (key, 0600 | IPC_CREAT);
46cec291
RS
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. */
e397a017 527#ifdef BSD_SYSTEM
46cec291
RS
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 {
bd252662 544#ifdef BSD_SYSTEM
26396b1b 545 fprintf (stderr, "%s: %s\n", argv[0], cwd);
bd252662
RS
546#else
547 fprintf (stderr, "%s: Cannot get current working directory: %s\n",
548 argv[0], strerror (errno));
549#endif
97e3214d 550 fail (argc, argv);
46cec291
RS
551 }
552
553 msgp->mtext[0] = 0;
1518a9eb 554 used = 0;
5212210c
RS
555
556 if (nowait)
557 {
558 strcat (msgp->mtext, "-nowait ");
559 used += 8;
560 }
561
562 argc -= optind;
563 argv += optind;
564
46cec291
RS
565 while (argc)
566 {
1518a9eb 567 int need_cwd = 0;
cd33a5a0 568 char *modified_arg = argv[0];
292d74a3 569
5212210c 570 if (*modified_arg == '+')
46cec291 571 {
cd33a5a0 572 char *p = modified_arg + 1;
8b8f50f8
GM
573 while (isdigit (*p) || *p == ':')
574 p++;
46cec291 575 if (*p != 0)
1518a9eb 576 need_cwd = 1;
46cec291 577 }
cd33a5a0 578 else if (*modified_arg != '/')
1518a9eb
RS
579 need_cwd = 1;
580
5212210c
RS
581 modified_arg = quote_file_name (modified_arg);
582
1518a9eb 583 if (need_cwd)
0343a017
KH
584 /* Overestimate in case we have to quote something in CWD. */
585 used += 2 * strlen (cwd);
cd33a5a0 586 used += strlen (modified_arg) + 1;
1518a9eb
RS
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)
0343a017 596 strcat (msgp->mtext, quote_file_name (cwd));
46cec291 597
cd33a5a0 598 strcat (msgp->mtext, modified_arg);
46cec291
RS
599 strcat (msgp->mtext, " ");
600 argv++; argc--;
601 }
602 strcat (msgp->mtext, "\n");
1518a9eb
RS
603#ifdef HPUX /* HPUX has a bug. */
604 if (strlen (msgp->mtext) >= 512)
605 {
18a2fa91 606 fprintf (stderr, "%s: args too long for msgsnd\n", progname);
97e3214d 607 fail (argc, argv);
1518a9eb
RS
608 }
609#endif
46cec291
RS
610 msgp->mtype = 1;
611 if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
612 {
defb80d7 613 fprintf (stderr, "%s: ", progname);
46cec291 614 perror ("msgsnd");
97e3214d 615 fail (argc, argv);
46cec291 616 }
292d74a3
RS
617
618 /* Maybe wait for an answer. */
619 if (nowait)
620 return 0;
621
46cec291
RS
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
dc3c30fe
KH
628 printf ("\n");
629 if (*buf)
630 printf ("%s\n", buf);
46cec291
RS
631 exit (0);
632}
633
634#endif /* HAVE_SYSVIPC */
635
636#endif /* HAVE_SOCKETS or HAVE_SYSVIPC */
27711600
RM
637\f
638#ifndef HAVE_STRERROR
639char *
640strerror (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 */