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