Commit | Line | Data |
---|---|---|
efb859b4 | 1 | /* Client process that communicates with GNU Emacs acting as server. |
92b47a4a | 2 | Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004, |
273dc16a | 3 | 2005, 2006 Free Software Foundation, Inc. |
46cec291 RS |
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 | |
92af894f | 9 | the Free Software Foundation; either version 2, or (at your option) |
46cec291 RS |
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 | |
364c38d3 LK |
19 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | Boston, MA 02110-1301, 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 | ||
aa0b6932 | 29 | #ifdef WINDOWSNT |
aa0b6932 | 30 | |
411b80a5 JB |
31 | # include <malloc.h> |
32 | # include <stdlib.h> | |
33 | ||
34 | # define HAVE_SOCKETS | |
1e7823d0 | 35 | # define HAVE_INET_SOCKETS |
411b80a5 JB |
36 | # define NO_SOCKETS_IN_FILE_SYSTEM |
37 | ||
aa0b6932 JB |
38 | # define HSOCKET SOCKET |
39 | # define CLOSE_SOCKET closesocket | |
aa0b6932 | 40 | # define INITIALIZE() (initialize_sockets ()) |
411b80a5 JB |
41 | |
42 | #else /* !WINDOWSNT */ | |
43 | ||
1e7823d0 JB |
44 | # ifdef HAVE_INET_SOCKETS |
45 | # include <netinet/in.h> | |
46 | # endif | |
411b80a5 | 47 | |
e35fc962 | 48 | # define INVALID_SOCKET -1 |
aa0b6932 JB |
49 | # define HSOCKET int |
50 | # define CLOSE_SOCKET close | |
aa0b6932 | 51 | # define INITIALIZE() |
411b80a5 JB |
52 | |
53 | #endif /* !WINDOWSNT */ | |
aa0b6932 | 54 | |
4e23f2ba | 55 | #undef signal |
46cec291 | 56 | |
e69233c2 | 57 | #include <ctype.h> |
8f9aaa0a | 58 | #include <stdio.h> |
aa0b6932 | 59 | #include "getopt.h" |
79f13bba DL |
60 | #ifdef HAVE_UNISTD_H |
61 | #include <unistd.h> | |
62 | #endif | |
8f9aaa0a | 63 | |
9f637eea GM |
64 | #ifdef VMS |
65 | # include "vms-pwd.h" | |
aa0b6932 JB |
66 | #else /* not VMS */ |
67 | #ifdef WINDOWSNT | |
68 | # include <io.h> | |
69 | #else /* not WINDOWSNT */ | |
9f637eea | 70 | # include <pwd.h> |
aa0b6932 | 71 | #endif /* not WINDOWSNT */ |
9f637eea GM |
72 | #endif /* not VMS */ |
73 | ||
8f9aaa0a | 74 | char *getenv (), *getwd (); |
5b9562c3 | 75 | char *(getcwd) (); |
8f9aaa0a | 76 | |
8f9aaa0a RS |
77 | #ifndef VERSION |
78 | #define VERSION "unspecified" | |
79 | #endif | |
80 | \f | |
aa0b6932 JB |
81 | #define SEND_STRING(data) (send_to_emacs (s, (data))) |
82 | #define SEND_QUOTED(data) (quote_file_name (s, (data))) | |
83 | ||
84 | #ifndef EXIT_SUCCESS | |
85 | #define EXIT_SUCCESS 0 | |
86 | #endif | |
87 | ||
88 | #ifndef EXIT_FAILURE | |
89 | #define EXIT_FAILURE 1 | |
90 | #endif | |
91 | ||
92 | #ifndef FALSE | |
93 | #define FALSE 0 | |
94 | #endif | |
95 | ||
96 | #ifndef TRUE | |
97 | #define TRUE 1 | |
98 | #endif | |
99 | ||
100 | #ifndef NO_RETURN | |
101 | #define NO_RETURN | |
102 | #endif | |
103 | \f | |
8f9aaa0a RS |
104 | /* Name used to invoke this program. */ |
105 | char *progname; | |
106 | ||
749ae770 | 107 | /* Nonzero means don't wait for a response from Emacs. --no-wait. */ |
8f9aaa0a RS |
108 | int nowait = 0; |
109 | ||
30be2360 SM |
110 | /* Nonzero means args are expressions to be evaluated. --eval. */ |
111 | int eval = 0; | |
112 | ||
113 | /* The display on which Emacs should work. --display. */ | |
114 | char *display = NULL; | |
115 | ||
116 | /* If non-NULL, the name of an editor to fallback to if the server | |
117 | is not running. --alternate-editor. */ | |
b03d27bd | 118 | const char *alternate_editor = NULL; |
30be2360 | 119 | |
3db926be | 120 | /* If non-NULL, the filename of the UNIX socket. */ |
254107e4 RS |
121 | char *socket_name = NULL; |
122 | ||
aa0b6932 JB |
123 | /* If non-NULL, the filename of the authentication file. */ |
124 | char *server_file = NULL; | |
125 | ||
2381d38d | 126 | void print_help_and_exit () NO_RETURN; |
7f3bff3e | 127 | |
8f9aaa0a RS |
128 | struct option longopts[] = |
129 | { | |
749ae770 | 130 | { "no-wait", no_argument, NULL, 'n' }, |
30be2360 | 131 | { "eval", no_argument, NULL, 'e' }, |
8f9aaa0a RS |
132 | { "help", no_argument, NULL, 'H' }, |
133 | { "version", no_argument, NULL, 'V' }, | |
3cf8c6aa | 134 | { "alternate-editor", required_argument, NULL, 'a' }, |
b03d27bd | 135 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM |
254107e4 | 136 | { "socket-name", required_argument, NULL, 's' }, |
b03d27bd | 137 | #endif |
aa0b6932 | 138 | { "server-file", required_argument, NULL, 'f' }, |
30be2360 SM |
139 | { "display", required_argument, NULL, 'd' }, |
140 | { 0, 0, 0, 0 } | |
8f9aaa0a RS |
141 | }; |
142 | ||
143 | /* Decode the options from argv and argc. | |
5212210c | 144 | The global variable `optind' will say how many arguments we used up. */ |
8f9aaa0a | 145 | |
5212210c | 146 | void |
8f9aaa0a RS |
147 | decode_options (argc, argv) |
148 | int argc; | |
149 | char **argv; | |
150 | { | |
b6b6d6d2 SM |
151 | alternate_editor = getenv ("ALTERNATE_EDITOR"); |
152 | ||
8f9aaa0a RS |
153 | while (1) |
154 | { | |
155 | int opt = getopt_long (argc, argv, | |
b03d27bd JB |
156 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM |
157 | "VHnea:s:f:d:", | |
158 | #else | |
159 | "VHnea:f:d:", | |
160 | #endif | |
161 | longopts, 0); | |
8f9aaa0a RS |
162 | |
163 | if (opt == EOF) | |
164 | break; | |
165 | ||
166 | switch (opt) | |
167 | { | |
168 | case 0: | |
169 | /* If getopt returns 0, then it has already processed a | |
170 | long-named option. We should do nothing. */ | |
171 | break; | |
e69233c2 | 172 | |
97e3214d GM |
173 | case 'a': |
174 | alternate_editor = optarg; | |
175 | break; | |
e69233c2 | 176 | |
b03d27bd | 177 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM |
254107e4 RS |
178 | case 's': |
179 | socket_name = optarg; | |
180 | break; | |
b03d27bd | 181 | #endif |
254107e4 | 182 | |
aa0b6932 JB |
183 | case 'f': |
184 | server_file = optarg; | |
185 | break; | |
186 | ||
30be2360 SM |
187 | case 'd': |
188 | display = optarg; | |
189 | break; | |
190 | ||
8f9aaa0a RS |
191 | case 'n': |
192 | nowait = 1; | |
193 | break; | |
194 | ||
30be2360 SM |
195 | case 'e': |
196 | eval = 1; | |
197 | break; | |
198 | ||
8f9aaa0a | 199 | case 'V': |
20c396e8 | 200 | printf ("emacsclient %s\n", VERSION); |
65396510 | 201 | exit (EXIT_SUCCESS); |
8f9aaa0a | 202 | break; |
46cec291 | 203 | |
8f9aaa0a | 204 | case 'H': |
8f9aaa0a | 205 | print_help_and_exit (); |
20c396e8 JB |
206 | break; |
207 | ||
208 | default: | |
209 | fprintf (stderr, "Try `%s --help' for more information\n", progname); | |
65396510 | 210 | exit (EXIT_FAILURE); |
20c396e8 | 211 | break; |
8f9aaa0a RS |
212 | } |
213 | } | |
8f9aaa0a RS |
214 | } |
215 | ||
7f3bff3e | 216 | void |
8f9aaa0a RS |
217 | print_help_and_exit () |
218 | { | |
20c396e8 JB |
219 | printf ( |
220 | "Usage: %s [OPTIONS] FILE...\n\ | |
30be2360 SM |
221 | Tell the Emacs server to visit the specified files.\n\ |
222 | Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\ | |
20c396e8 | 223 | \n\ |
30be2360 SM |
224 | The following OPTIONS are accepted:\n\ |
225 | -V, --version Just print a version info and return\n\ | |
226 | -H, --help Print this usage information message\n\ | |
227 | -n, --no-wait Don't wait for the server to return\n\ | |
228 | -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ | |
aa0b6932 JB |
229 | -d, --display=DISPLAY Visit the file in the given display\n" |
230 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM | |
231 | "-s, --socket-name=FILENAME\n\ | |
232 | Set the filename of the UNIX socket for communication\n" | |
233 | #endif | |
234 | "-f, --server-file=FILENAME\n\ | |
235 | Set the filename of the TCP configuration file\n\ | |
30be2360 SM |
236 | -a, --alternate-editor=EDITOR\n\ |
237 | Editor to fallback to if the server is not running\n\ | |
20c396e8 | 238 | \n\ |
30be2360 | 239 | Report bugs to bug-gnu-emacs@gnu.org.\n", progname); |
65396510 | 240 | exit (EXIT_SUCCESS); |
8f9aaa0a | 241 | } |
5212210c | 242 | |
aa0b6932 JB |
243 | \f |
244 | /* | |
245 | Try to run a different command, or --if no alternate editor is | |
246 | defined-- exit with an errorcode. | |
247 | */ | |
248 | void | |
249 | fail (argc, argv) | |
250 | int argc; | |
251 | char **argv; | |
252 | { | |
253 | if (alternate_editor) | |
254 | { | |
255 | int i = optind - 1; | |
b73ea44b JB |
256 | #ifdef WINDOWSNT |
257 | argv[i] = (char *)alternate_editor; | |
258 | #endif | |
aa0b6932 JB |
259 | execvp (alternate_editor, argv + i); |
260 | fprintf (stderr, "%s: error executing alternate editor \"%s\"\n", | |
261 | progname, alternate_editor); | |
262 | } | |
aa0b6932 JB |
263 | exit (EXIT_FAILURE); |
264 | } | |
265 | ||
266 | \f | |
1e7823d0 | 267 | #if !defined (HAVE_SOCKETS) || !defined (HAVE_INET_SOCKETS) |
aa0b6932 JB |
268 | |
269 | int | |
270 | main (argc, argv) | |
271 | int argc; | |
272 | char **argv; | |
273 | { | |
274 | fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n", | |
275 | argv[0]); | |
276 | fprintf (stderr, "on systems with Berkeley sockets.\n"); | |
277 | ||
278 | fail (argc, argv); | |
279 | } | |
280 | ||
1e7823d0 | 281 | #else /* HAVE_SOCKETS && HAVE_INET_SOCKETS */ |
aa0b6932 JB |
282 | |
283 | #ifdef WINDOWSNT | |
284 | # include <winsock2.h> | |
285 | #else | |
286 | # include <sys/types.h> | |
287 | # include <sys/socket.h> | |
288 | # include <sys/un.h> | |
289 | # include <sys/stat.h> | |
290 | # include <errno.h> | |
291 | #endif | |
292 | ||
293 | #define AUTH_KEY_LENGTH 64 | |
294 | #define SEND_BUFFER_SIZE 4096 | |
295 | ||
296 | extern char *strerror (); | |
297 | extern int errno; | |
298 | ||
299 | /* Buffer to accumulate data to send in TCP connections. */ | |
300 | char send_buffer[SEND_BUFFER_SIZE + 1]; | |
301 | int sblen = 0; /* Fill pointer for the send buffer. */ | |
302 | ||
303 | /* Let's send the data to Emacs when either | |
304 | - the data ends in "\n", or | |
305 | - the buffer is full (but this shouldn't happen) | |
306 | Otherwise, we just accumulate it. */ | |
b03d27bd JB |
307 | void |
308 | send_to_emacs (s, data) | |
aa0b6932 JB |
309 | HSOCKET s; |
310 | char *data; | |
311 | { | |
312 | while (data) | |
313 | { | |
314 | int dlen = strlen (data); | |
315 | if (dlen + sblen >= SEND_BUFFER_SIZE) | |
316 | { | |
317 | int part = SEND_BUFFER_SIZE - sblen; | |
318 | strncpy (&send_buffer[sblen], data, part); | |
319 | data += part; | |
320 | sblen = SEND_BUFFER_SIZE; | |
321 | } | |
322 | else if (dlen) | |
323 | { | |
324 | strcpy (&send_buffer[sblen], data); | |
325 | data = NULL; | |
326 | sblen += dlen; | |
327 | } | |
328 | else | |
329 | break; | |
330 | ||
331 | if (sblen == SEND_BUFFER_SIZE | |
332 | || (sblen > 0 && send_buffer[sblen-1] == '\n')) | |
333 | { | |
334 | int sent = send (s, send_buffer, sblen, 0); | |
335 | if (sent != sblen) | |
336 | strcpy (send_buffer, &send_buffer[sent]); | |
337 | sblen -= sent; | |
338 | } | |
339 | } | |
340 | } | |
341 | ||
a4cf2096 RS |
342 | /* In NAME, insert a & before each &, each space, each newline, and |
343 | any initial -. Change spaces to underscores, too, so that the | |
5212210c | 344 | return value never contains a space. */ |
87209357 | 345 | void |
aa0b6932 JB |
346 | quote_file_name (s, name) |
347 | HSOCKET s; | |
5212210c RS |
348 | char *name; |
349 | { | |
350 | char *copy = (char *) malloc (strlen (name) * 2 + 1); | |
351 | char *p, *q; | |
352 | ||
353 | p = name; | |
354 | q = copy; | |
355 | while (*p) | |
356 | { | |
357 | if (*p == ' ') | |
358 | { | |
f1db6a73 | 359 | *q++ = '&'; |
5212210c RS |
360 | *q++ = '_'; |
361 | p++; | |
362 | } | |
3cf8c6aa SM |
363 | else if (*p == '\n') |
364 | { | |
365 | *q++ = '&'; | |
366 | *q++ = 'n'; | |
367 | p++; | |
368 | } | |
5212210c RS |
369 | else |
370 | { | |
f1db6a73 RS |
371 | if (*p == '&' || (*p == '-' && p == name)) |
372 | *q++ = '&'; | |
5212210c RS |
373 | *q++ = *p++; |
374 | } | |
375 | } | |
f1db6a73 | 376 | *q++ = 0; |
5212210c | 377 | |
aa0b6932 | 378 | SEND_STRING (copy); |
87209357 EZ |
379 | |
380 | free (copy); | |
5212210c | 381 | } |
0c76956f | 382 | |
b03d27bd JB |
383 | int |
384 | file_name_absolute_p (filename) | |
385 | const unsigned char *filename; | |
386 | { | |
387 | /* Sanity check, it shouldn't happen. */ | |
388 | if (! filename) return FALSE; | |
389 | ||
390 | /* /xxx is always an absolute path. */ | |
391 | if (filename[0] == '/') return TRUE; | |
392 | ||
393 | /* Empty filenames (which shouldn't happen) are relative. */ | |
394 | if (filename[0] == '\0') return FALSE; | |
395 | ||
396 | #ifdef WINDOWSNT | |
397 | /* X:\xxx is always absolute; X:xxx is an error and will fail. */ | |
398 | if (islower (tolower (filename[0])) | |
399 | && filename[1] == ':' && filename[2] == '\\') | |
400 | return TRUE; | |
401 | ||
402 | /* Both \xxx and \\xxx\yyy are absolute. */ | |
403 | if (filename[0] == '\\') return TRUE; | |
404 | #endif | |
405 | ||
406 | return FALSE; | |
407 | } | |
408 | ||
aa0b6932 JB |
409 | #ifdef WINDOWSNT |
410 | /* Wrapper to make WSACleanup a cdecl, as required by atexit(). */ | |
b03d27bd JB |
411 | void |
412 | __cdecl close_winsock () | |
aa0b6932 JB |
413 | { |
414 | WSACleanup (); | |
415 | } | |
0c76956f | 416 | |
b03d27bd JB |
417 | /* Initialize the WinSock2 library. */ |
418 | void | |
419 | initialize_sockets () | |
0c76956f | 420 | { |
aa0b6932 JB |
421 | WSADATA wsaData; |
422 | ||
aa0b6932 JB |
423 | if (WSAStartup (MAKEWORD (2, 0), &wsaData)) |
424 | { | |
425 | fprintf (stderr, "%s: error initializing WinSock2", progname); | |
426 | exit (EXIT_FAILURE); | |
427 | } | |
428 | ||
429 | atexit (close_winsock); | |
0c76956f | 430 | } |
e35fc962 | 431 | #endif /* WINDOWSNT */ |
8f9aaa0a | 432 | \f |
97e3214d | 433 | /* |
aa0b6932 JB |
434 | * Read the information needed to set up a TCP comm channel with |
435 | * the Emacs server: host, port and authentication string. | |
97e3214d | 436 | */ |
b03d27bd JB |
437 | int |
438 | get_server_config (server, authentication) | |
aa0b6932 JB |
439 | struct sockaddr_in *server; |
440 | char *authentication; | |
97e3214d | 441 | { |
aa0b6932 JB |
442 | char dotted[32]; |
443 | char *port; | |
b03d27bd | 444 | FILE *config = NULL; |
aa0b6932 | 445 | |
b03d27bd JB |
446 | if (file_name_absolute_p (server_file)) |
447 | config = fopen (server_file, "rb"); | |
448 | else | |
97e3214d | 449 | { |
aa0b6932 JB |
450 | char *home = getenv ("HOME"); |
451 | #ifdef WINDOWSNT | |
452 | if (! home) | |
453 | home = getenv ("APPDATA"); | |
454 | #endif | |
455 | if (home) | |
456 | { | |
457 | char *path = alloca (32 + strlen (home) + strlen (server_file)); | |
458 | sprintf (path, "%s/.emacs.d/server/%s", home, server_file); | |
459 | config = fopen (path, "rb"); | |
460 | } | |
461 | } | |
462 | ||
463 | if (! config) | |
464 | return FALSE; | |
465 | ||
466 | if (fgets (dotted, sizeof dotted, config) | |
467 | && (port = strchr (dotted, ':'))) | |
468 | { | |
469 | *port++ = '\0'; | |
97e3214d GM |
470 | } |
471 | else | |
472 | { | |
aa0b6932 | 473 | fprintf (stderr, "%s: invalid configuration info", progname); |
65396510 | 474 | exit (EXIT_FAILURE); |
97e3214d | 475 | } |
97e3214d | 476 | |
aa0b6932 JB |
477 | server->sin_family = AF_INET; |
478 | server->sin_addr.s_addr = inet_addr (dotted); | |
479 | server->sin_port = htons (atoi (port)); | |
97e3214d | 480 | |
aa0b6932 JB |
481 | if (! fread (authentication, AUTH_KEY_LENGTH, 1, config)) |
482 | { | |
483 | fprintf (stderr, "%s: cannot read authentication info", progname); | |
484 | exit (EXIT_FAILURE); | |
485 | } | |
46cec291 | 486 | |
aa0b6932 | 487 | fclose (config); |
97e3214d | 488 | |
aa0b6932 | 489 | return TRUE; |
46cec291 RS |
490 | } |
491 | ||
aa0b6932 JB |
492 | HSOCKET |
493 | set_tcp_socket () | |
494 | { | |
495 | HSOCKET s; | |
496 | struct sockaddr_in server; | |
aa0b6932 JB |
497 | struct linger l_arg = {1, 1}; |
498 | char auth_string[AUTH_KEY_LENGTH + 1]; | |
46cec291 | 499 | |
aa0b6932 JB |
500 | if (! get_server_config (&server, auth_string)) |
501 | return INVALID_SOCKET; | |
502 | ||
b03d27bd JB |
503 | if (server.sin_addr.s_addr != inet_addr ("127.0.0.1")) |
504 | fprintf (stderr, "%s: connected to remote socket at %s\n", | |
505 | progname, inet_ntoa (server.sin_addr)); | |
506 | ||
aa0b6932 JB |
507 | /* |
508 | * Open up an AF_INET socket | |
509 | */ | |
510 | if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
511 | { | |
512 | fprintf (stderr, "%s: ", progname); | |
513 | perror ("socket"); | |
514 | return INVALID_SOCKET; | |
515 | } | |
516 | ||
517 | /* | |
518 | * Set up the socket | |
519 | */ | |
520 | if (connect (s, (struct sockaddr *) &server, sizeof server) < 0) | |
521 | { | |
522 | fprintf (stderr, "%s: ", progname); | |
523 | perror ("connect"); | |
524 | return INVALID_SOCKET; | |
525 | } | |
526 | ||
aa0b6932 JB |
527 | setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg); |
528 | ||
529 | /* | |
530 | * Send the authentication | |
531 | */ | |
532 | auth_string[AUTH_KEY_LENGTH] = '\0'; | |
533 | ||
534 | SEND_STRING ("-auth "); | |
535 | SEND_STRING (auth_string); | |
536 | SEND_STRING ("\n"); | |
537 | ||
538 | return s; | |
539 | } | |
540 | ||
541 | #if !defined (NO_SOCKETS_IN_FILE_SYSTEM) | |
46cec291 | 542 | |
9f637eea GM |
543 | /* Three possibilities: |
544 | 2 - can't be `stat'ed (sets errno) | |
545 | 1 - isn't owned by us | |
546 | 0 - success: none of the above */ | |
547 | ||
548 | static int | |
549 | socket_status (socket_name) | |
550 | char *socket_name; | |
551 | { | |
552 | struct stat statbfr; | |
553 | ||
554 | if (stat (socket_name, &statbfr) == -1) | |
555 | return 2; | |
556 | ||
557 | if (statbfr.st_uid != geteuid ()) | |
558 | return 1; | |
559 | ||
560 | return 0; | |
561 | } | |
562 | ||
aa0b6932 JB |
563 | HSOCKET |
564 | set_local_socket () | |
46cec291 | 565 | { |
aa0b6932 | 566 | HSOCKET s; |
46cec291 | 567 | struct sockaddr_un server; |
46cec291 | 568 | |
e69233c2 | 569 | /* |
46cec291 RS |
570 | * Open up an AF_UNIX socket in this person's home directory |
571 | */ | |
572 | ||
573 | if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) | |
574 | { | |
aa0b6932 | 575 | fprintf (stderr, "%s: ", progname); |
46cec291 | 576 | perror ("socket"); |
aa0b6932 | 577 | return INVALID_SOCKET; |
46cec291 | 578 | } |
e69233c2 | 579 | |
46cec291 | 580 | server.sun_family = AF_UNIX; |
c5fee545 | 581 | |
c5fee545 | 582 | { |
9f637eea | 583 | int sock_status = 0; |
5c9659d3 | 584 | int default_sock = !socket_name; |
152b6e83 | 585 | int saved_errno; |
0734b0d0 SM |
586 | char *server_name = "server"; |
587 | ||
588 | if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) | |
589 | { /* socket_name is a file name component. */ | |
590 | server_name = socket_name; | |
591 | socket_name = NULL; | |
592 | default_sock = 1; /* Try both UIDs. */ | |
593 | } | |
efb859b4 | 594 | |
5c9659d3 | 595 | if (default_sock) |
254107e4 | 596 | { |
0734b0d0 SM |
597 | socket_name = alloca (100 + strlen (server_name)); |
598 | sprintf (socket_name, "/tmp/emacs%d/%s", | |
599 | (int) geteuid (), server_name); | |
254107e4 RS |
600 | } |
601 | ||
602 | if (strlen (socket_name) < sizeof (server.sun_path)) | |
603 | strcpy (server.sun_path, socket_name); | |
604 | else | |
5c9659d3 SM |
605 | { |
606 | fprintf (stderr, "%s: socket-name %s too long", | |
aa0b6932 | 607 | progname, socket_name); |
65396510 | 608 | exit (EXIT_FAILURE); |
5c9659d3 | 609 | } |
efb859b4 | 610 | |
9f637eea GM |
611 | /* See if the socket exists, and if it's owned by us. */ |
612 | sock_status = socket_status (server.sun_path); | |
152b6e83 | 613 | saved_errno = errno; |
5c9659d3 | 614 | if (sock_status && default_sock) |
efb859b4 | 615 | { |
9f637eea GM |
616 | /* Failing that, see if LOGNAME or USER exist and differ from |
617 | our euid. If so, look for a socket based on the UID | |
618 | associated with the name. This is reminiscent of the logic | |
619 | that init_editfns uses to set the global Vuser_full_name. */ | |
e69233c2 | 620 | |
9f637eea | 621 | char *user_name = (char *) getenv ("LOGNAME"); |
293f9f2a | 622 | |
9f637eea GM |
623 | if (!user_name) |
624 | user_name = (char *) getenv ("USER"); | |
e69233c2 | 625 | |
9f637eea GM |
626 | if (user_name) |
627 | { | |
628 | struct passwd *pw = getpwnam (user_name); | |
293f9f2a | 629 | |
9f637eea GM |
630 | if (pw && (pw->pw_uid != geteuid ())) |
631 | { | |
632 | /* We're running under su, apparently. */ | |
0734b0d0 SM |
633 | socket_name = alloca (100 + strlen (server_name)); |
634 | sprintf (socket_name, "/tmp/emacs%d/%s", | |
635 | (int) pw->pw_uid, server_name); | |
5c9659d3 SM |
636 | |
637 | if (strlen (socket_name) < sizeof (server.sun_path)) | |
638 | strcpy (server.sun_path, socket_name); | |
639 | else | |
640 | { | |
641 | fprintf (stderr, "%s: socket-name %s too long", | |
aa0b6932 | 642 | progname, socket_name); |
65396510 | 643 | exit (EXIT_FAILURE); |
5c9659d3 SM |
644 | } |
645 | ||
9f637eea | 646 | sock_status = socket_status (server.sun_path); |
152b6e83 | 647 | saved_errno = errno; |
9f637eea | 648 | } |
293f9f2a RS |
649 | else |
650 | errno = saved_errno; | |
9f637eea | 651 | } |
efb859b4 | 652 | } |
e69233c2 | 653 | |
aa0b6932 JB |
654 | switch (sock_status) |
655 | { | |
656 | case 1: | |
657 | /* There's a socket, but it isn't owned by us. This is OK if | |
658 | we are root. */ | |
659 | if (0 != geteuid ()) | |
660 | { | |
e35fc962 | 661 | fprintf (stderr, "%s: Invalid socket owner\n", progname); |
aa0b6932 JB |
662 | return INVALID_SOCKET; |
663 | } | |
664 | break; | |
665 | ||
666 | case 2: | |
667 | /* `stat' failed */ | |
668 | if (saved_errno == ENOENT) | |
669 | fprintf (stderr, | |
670 | "%s: can't find socket; have you started the server?\n\ | |
45adde32 | 671 | To start the server in Emacs, type \"M-x server-start\".\n", |
aa0b6932 JB |
672 | progname); |
673 | else | |
674 | fprintf (stderr, "%s: can't stat %s: %s\n", | |
675 | progname, server.sun_path, strerror (saved_errno)); | |
b03d27bd | 676 | return INVALID_SOCKET; |
aa0b6932 | 677 | } |
efb859b4 | 678 | } |
46cec291 | 679 | |
4e23f2ba JB |
680 | if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2) |
681 | < 0) | |
46cec291 | 682 | { |
aa0b6932 | 683 | fprintf (stderr, "%s: ", progname); |
46cec291 | 684 | perror ("connect"); |
aa0b6932 | 685 | return INVALID_SOCKET; |
46cec291 | 686 | } |
23a7488d | 687 | |
aa0b6932 JB |
688 | return s; |
689 | } | |
690 | #endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */ | |
691 | ||
692 | HSOCKET | |
693 | set_socket () | |
694 | { | |
b03d27bd JB |
695 | HSOCKET s; |
696 | ||
697 | INITIALIZE (); | |
698 | ||
aa0b6932 | 699 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM |
b03d27bd JB |
700 | /* Explicit --socket-name argument. */ |
701 | if (socket_name) | |
702 | { | |
703 | s = set_local_socket (); | |
704 | if ((s != INVALID_SOCKET) || alternate_editor) | |
705 | return s; | |
706 | ||
707 | fprintf (stderr, "%s: error accessing socket \"%s\"", | |
708 | progname, socket_name); | |
709 | exit (EXIT_FAILURE); | |
710 | } | |
711 | #endif | |
712 | ||
713 | /* Explicit --server-file arg or EMACS_SERVER_FILE variable. */ | |
714 | if (!server_file) | |
715 | server_file = getenv ("EMACS_SERVER_FILE"); | |
716 | ||
717 | if (server_file) | |
46cec291 | 718 | { |
b03d27bd JB |
719 | s = set_tcp_socket (); |
720 | if ((s != INVALID_SOCKET) || alternate_editor) | |
721 | return s; | |
722 | ||
723 | fprintf (stderr, "%s: error accessing server file \"%s\"", | |
724 | progname, server_file); | |
725 | exit (EXIT_FAILURE); | |
46cec291 | 726 | } |
b03d27bd JB |
727 | |
728 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM | |
729 | /* Implicit local socket. */ | |
730 | s = set_local_socket (); | |
731 | if (s != INVALID_SOCKET) | |
732 | return s; | |
733 | #endif | |
734 | ||
735 | /* Implicit server file. */ | |
736 | server_file = "server"; | |
737 | s = set_tcp_socket (); | |
738 | if ((s != INVALID_SOCKET) || alternate_editor) | |
739 | return s; | |
740 | ||
741 | /* No implicit or explicit socket, and no alternate editor. */ | |
742 | fprintf (stderr, "%s: No socket or alternate editor. Please use:\n\n" | |
743 | #ifndef NO_SOCKETS_IN_FILE_SYSTEM | |
744 | "\t--socket-name\n" | |
aa0b6932 | 745 | #endif |
b03d27bd JB |
746 | "\t--server-file (or environment variable EMACS_SERVER_FILE)\n\ |
747 | \t--alternate-editor (or environment variable ALTERNATE_EDITOR)\n", | |
748 | progname); | |
749 | exit (EXIT_FAILURE); | |
aa0b6932 | 750 | } |
46cec291 | 751 | |
aa0b6932 JB |
752 | int |
753 | main (argc, argv) | |
754 | int argc; | |
755 | char **argv; | |
756 | { | |
757 | HSOCKET s; | |
758 | int i, rl, needlf = 0; | |
759 | char *cwd; | |
760 | char string[BUFSIZ+1]; | |
761 | ||
762 | progname = argv[0]; | |
763 | ||
764 | /* Process options. */ | |
765 | decode_options (argc, argv); | |
766 | ||
767 | if ((argc - optind < 1) && !eval) | |
23a7488d | 768 | { |
aa0b6932 JB |
769 | fprintf (stderr, "%s: file name or argument required\n", progname); |
770 | fprintf (stderr, "Try `%s --help' for more information\n", progname); | |
771 | exit (EXIT_FAILURE); | |
23a7488d RS |
772 | } |
773 | ||
aa0b6932 JB |
774 | if ((s = set_socket ()) == INVALID_SOCKET) |
775 | fail (argc, argv); | |
776 | ||
38732dba | 777 | #ifdef HAVE_GETCWD |
ee6a193c | 778 | cwd = getcwd (string, sizeof string); |
38732dba RS |
779 | #else |
780 | cwd = getwd (string); | |
ee6a193c | 781 | #endif |
46cec291 RS |
782 | if (cwd == 0) |
783 | { | |
784 | /* getwd puts message in STRING if it fails. */ | |
38732dba | 785 | #ifdef HAVE_GETCWD |
aa0b6932 | 786 | fprintf (stderr, "%s: %s (%s)\n", progname, |
bb5618fe | 787 | "Cannot get current working directory", strerror (errno)); |
38732dba | 788 | #else |
aa0b6932 | 789 | fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno)); |
bd252662 | 790 | #endif |
97e3214d | 791 | fail (argc, argv); |
46cec291 RS |
792 | } |
793 | ||
5212210c | 794 | if (nowait) |
aa0b6932 | 795 | SEND_STRING ("-nowait "); |
292d74a3 | 796 | |
30be2360 | 797 | if (eval) |
aa0b6932 | 798 | SEND_STRING ("-eval "); |
30be2360 SM |
799 | |
800 | if (display) | |
87209357 | 801 | { |
aa0b6932 JB |
802 | SEND_STRING ("-display "); |
803 | SEND_QUOTED (display); | |
804 | SEND_STRING (" "); | |
87209357 | 805 | } |
30be2360 | 806 | |
87209357 | 807 | if ((argc - optind > 0)) |
5212210c | 808 | { |
87209357 | 809 | for (i = optind; i < argc; i++) |
46cec291 | 810 | { |
87209357 EZ |
811 | if (eval) |
812 | ; /* Don't prepend any cwd or anything like that. */ | |
813 | else if (*argv[i] == '+') | |
814 | { | |
815 | char *p = argv[i] + 1; | |
816 | while (isdigit ((unsigned char) *p) || *p == ':') p++; | |
817 | if (*p != 0) | |
818 | { | |
aa0b6932 JB |
819 | SEND_QUOTED (cwd); |
820 | SEND_STRING ("/"); | |
87209357 EZ |
821 | } |
822 | } | |
b03d27bd | 823 | else if (! file_name_absolute_p (argv[i])) |
87209357 | 824 | { |
aa0b6932 JB |
825 | SEND_QUOTED (cwd); |
826 | SEND_STRING ("/"); | |
87209357 EZ |
827 | } |
828 | ||
aa0b6932 JB |
829 | SEND_QUOTED (argv[i]); |
830 | SEND_STRING (" "); | |
46cec291 | 831 | } |
46cec291 | 832 | } |
87209357 EZ |
833 | else |
834 | { | |
aa0b6932 | 835 | while (fgets (string, BUFSIZ, stdin)) |
87209357 | 836 | { |
aa0b6932 | 837 | SEND_QUOTED (string); |
87209357 | 838 | } |
aa0b6932 | 839 | SEND_STRING (" "); |
87209357 | 840 | } |
65396510 | 841 | |
aa0b6932 | 842 | SEND_STRING ("\n"); |
46cec291 | 843 | |
292d74a3 | 844 | /* Maybe wait for an answer. */ |
aa0b6932 | 845 | if (!nowait) |
30be2360 | 846 | { |
aa0b6932 JB |
847 | if (!eval) |
848 | { | |
849 | printf ("Waiting for Emacs..."); | |
850 | needlf = 2; | |
851 | } | |
852 | fflush (stdout); | |
853 | ||
854 | /* Now, wait for an answer and print any messages. */ | |
855 | while ((rl = recv (s, string, BUFSIZ, 0)) > 0) | |
856 | { | |
857 | string[rl] = '\0'; | |
858 | if (needlf == 2) | |
859 | printf ("\n"); | |
860 | printf ("%s", string); | |
861 | needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n'; | |
862 | } | |
863 | ||
864 | if (needlf) | |
865 | printf ("\n"); | |
866 | fflush (stdout); | |
30be2360 | 867 | } |
23a7488d | 868 | |
aa0b6932 | 869 | CLOSE_SOCKET (s); |
65396510 | 870 | return EXIT_SUCCESS; |
46cec291 RS |
871 | } |
872 | ||
1e7823d0 | 873 | #endif /* HAVE_SOCKETS && HAVE_INET_SOCKETS */ |
aa0b6932 | 874 | |
27711600 RM |
875 | #ifndef HAVE_STRERROR |
876 | char * | |
877 | strerror (errnum) | |
878 | int errnum; | |
879 | { | |
880 | extern char *sys_errlist[]; | |
881 | extern int sys_nerr; | |
882 | ||
883 | if (errnum >= 0 && errnum < sys_nerr) | |
884 | return sys_errlist[errnum]; | |
885 | return (char *) "Unknown error"; | |
886 | } | |
887 | ||
888 | #endif /* ! HAVE_STRERROR */ | |
ab5796a9 MB |
889 | |
890 | /* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7 | |
891 | (do not change this comment) */ | |
65396510 TTN |
892 | |
893 | /* emacsclient.c ends here */ |