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