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