comparison lib-src/emacsclient.c @ 89909:68c22ea6027c

Sync to HEAD
author Kenichi Handa <handa@m17n.org>
date Fri, 16 Apr 2004 12:51:06 +0000
parents 375f2633d815
children 4c90ffeb71c5
comparison
equal deleted inserted replaced
89908:ee1402f7b568 89909:68c22ea6027c
1 /* Client process that communicates with GNU Emacs acting as server. 1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003 2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003, 2004
3 Free Software Foundation, Inc. 3 Free Software Foundation, Inc.
4 4
5 This file is part of GNU Emacs. 5 This file is part of GNU Emacs.
6 6
7 GNU Emacs is free software; you can redistribute it and/or modify 7 GNU Emacs is free software; you can redistribute it and/or modify
65 65
66 /* If non-NULL, the name of an editor to fallback to if the server 66 /* If non-NULL, the name of an editor to fallback to if the server
67 is not running. --alternate-editor. */ 67 is not running. --alternate-editor. */
68 const char * alternate_editor = NULL; 68 const char * alternate_editor = NULL;
69 69
70 /* If non-NULL, the filename of the UNIX socket. */
71 char *socket_name = NULL;
72
70 void print_help_and_exit (); 73 void print_help_and_exit ();
71 74
72 struct option longopts[] = 75 struct option longopts[] =
73 { 76 {
74 { "no-wait", no_argument, NULL, 'n' }, 77 { "no-wait", no_argument, NULL, 'n' },
75 { "eval", no_argument, NULL, 'e' }, 78 { "eval", no_argument, NULL, 'e' },
76 { "help", no_argument, NULL, 'H' }, 79 { "help", no_argument, NULL, 'H' },
77 { "version", no_argument, NULL, 'V' }, 80 { "version", no_argument, NULL, 'V' },
78 { "alternate-editor", required_argument, NULL, 'a' }, 81 { "alternate-editor", required_argument, NULL, 'a' },
82 { "socket-name", required_argument, NULL, 's' },
79 { "display", required_argument, NULL, 'd' }, 83 { "display", required_argument, NULL, 'd' },
80 { 0, 0, 0, 0 } 84 { 0, 0, 0, 0 }
81 }; 85 };
82 86
83 /* Decode the options from argv and argc. 87 /* Decode the options from argv and argc.
86 void 90 void
87 decode_options (argc, argv) 91 decode_options (argc, argv)
88 int argc; 92 int argc;
89 char **argv; 93 char **argv;
90 { 94 {
95 alternate_editor = getenv ("ALTERNATE_EDITOR");
96
91 while (1) 97 while (1)
92 { 98 {
93 int opt = getopt_long (argc, argv, 99 int opt = getopt_long (argc, argv,
94 "VHnea:d:", longopts, 0); 100 "VHnea:s:d:", longopts, 0);
95 101
96 if (opt == EOF) 102 if (opt == EOF)
97 break; 103 break;
98
99 alternate_editor = getenv ("ALTERNATE_EDITOR");
100 104
101 switch (opt) 105 switch (opt)
102 { 106 {
103 case 0: 107 case 0:
104 /* If getopt returns 0, then it has already processed a 108 /* If getopt returns 0, then it has already processed a
105 long-named option. We should do nothing. */ 109 long-named option. We should do nothing. */
106 break; 110 break;
107 111
108 case 'a': 112 case 'a':
109 alternate_editor = optarg; 113 alternate_editor = optarg;
114 break;
115
116 case 's':
117 socket_name = optarg;
110 break; 118 break;
111 119
112 case 'd': 120 case 'd':
113 display = optarg; 121 display = optarg;
114 break; 122 break;
150 -V, --version Just print a version info and return\n\ 158 -V, --version Just print a version info and return\n\
151 -H, --help Print this usage information message\n\ 159 -H, --help Print this usage information message\n\
152 -n, --no-wait Don't wait for the server to return\n\ 160 -n, --no-wait Don't wait for the server to return\n\
153 -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ 161 -e, --eval Evaluate the FILE arguments as ELisp expressions\n\
154 -d, --display=DISPLAY Visit the file in the given display\n\ 162 -d, --display=DISPLAY Visit the file in the given display\n\
163 -s, --socket-name=FILENAME\n\
164 Set the filename of the UNIX socket for communication\n\
155 -a, --alternate-editor=EDITOR\n\ 165 -a, --alternate-editor=EDITOR\n\
156 Editor to fallback to if the server is not running\n\ 166 Editor to fallback to if the server is not running\n\
157 \n\ 167 \n\
158 Report bugs to bug-gnu-emacs@gnu.org.\n", progname); 168 Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
159 exit (0); 169 exit (0);
160 } 170 }
161 171
162 /* Return a copy of NAME, inserting a & 172 /* In NAME, insert a & before each &, each space, each newline, and
163 before each &, each space, each newline, and any initial -. 173 any initial -. Change spaces to underscores, too, so that the
164 Change spaces to underscores, too, so that the
165 return value never contains a space. */ 174 return value never contains a space. */
166 175
167 char * 176 void
168 quote_file_name (name) 177 quote_file_name (name, stream)
169 char *name; 178 char *name;
179 FILE *stream;
170 { 180 {
171 char *copy = (char *) malloc (strlen (name) * 2 + 1); 181 char *copy = (char *) malloc (strlen (name) * 2 + 1);
172 char *p, *q; 182 char *p, *q;
173 183
174 p = name; 184 p = name;
194 *q++ = *p++; 204 *q++ = *p++;
195 } 205 }
196 } 206 }
197 *q++ = 0; 207 *q++ = 0;
198 208
199 return copy; 209 fprintf (stream, copy);
210
211 free (copy);
200 } 212 }
201 213
202 /* Like malloc but get fatal error if memory is exhausted. */ 214 /* Like malloc but get fatal error if memory is exhausted. */
203 215
204 long * 216 long *
285 int 297 int
286 main (argc, argv) 298 main (argc, argv)
287 int argc; 299 int argc;
288 char **argv; 300 char **argv;
289 { 301 {
290 char *system_name;
291 int system_name_length;
292 int s, i, needlf = 0; 302 int s, i, needlf = 0;
293 FILE *out, *in; 303 FILE *out, *in;
294 struct sockaddr_un server; 304 struct sockaddr_un server;
295 char *cwd, *str; 305 char *cwd, *str;
296 char string[BUFSIZ]; 306 char string[BUFSIZ];
298 progname = argv[0]; 308 progname = argv[0];
299 309
300 /* Process options. */ 310 /* Process options. */
301 decode_options (argc, argv); 311 decode_options (argc, argv);
302 312
303 if (argc - optind < 1) 313 if ((argc - optind < 1) && !eval)
304 { 314 {
305 fprintf (stderr, "%s: file name or argument required\n", progname); 315 fprintf (stderr, "%s: file name or argument required\n", progname);
306 fprintf (stderr, "Try `%s --help' for more information\n", progname); 316 fprintf (stderr, "Try `%s --help' for more information\n", progname);
307 exit (1); 317 exit (1);
308 } 318 }
319 } 329 }
320 330
321 server.sun_family = AF_UNIX; 331 server.sun_family = AF_UNIX;
322 332
323 { 333 {
324 char *dot; 334 int sock_status = 0;
325 system_name_length = 32; 335 int default_sock = !socket_name;
326 336 int saved_errno;
327 while (1) 337 char *server_name = "server";
338
339 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
340 { /* socket_name is a file name component. */
341 server_name = socket_name;
342 socket_name = NULL;
343 default_sock = 1; /* Try both UIDs. */
344 }
345
346 if (default_sock)
328 { 347 {
329 system_name = (char *) xmalloc (system_name_length + 1); 348 socket_name = alloca (100 + strlen (server_name));
330 349 sprintf (socket_name, "/tmp/emacs%d/%s",
331 /* system_name must be null-terminated string. */ 350 (int) geteuid (), server_name);
332 system_name[system_name_length] = '\0';
333
334 if (gethostname (system_name, system_name_length) == 0)
335 break;
336
337 free (system_name);
338 system_name_length *= 2;
339 } 351 }
340 352
341 /* We always use the non-dotted host name, for simplicity. */ 353 if (strlen (socket_name) < sizeof (server.sun_path))
342 dot = index (system_name, '.'); 354 strcpy (server.sun_path, socket_name);
343 if (dot) 355 else
344 *dot = '\0'; 356 {
345 } 357 fprintf (stderr, "%s: socket-name %s too long",
346 358 argv[0], socket_name);
347 { 359 exit (1);
348 int sock_status = 0; 360 }
349
350 sprintf (server.sun_path, "/tmp/emacs%d-%s/server", (int) geteuid (), system_name);
351 361
352 /* See if the socket exists, and if it's owned by us. */ 362 /* See if the socket exists, and if it's owned by us. */
353 sock_status = socket_status (server.sun_path); 363 sock_status = socket_status (server.sun_path);
354 if (sock_status) 364 saved_errno = errno;
365 if (sock_status && default_sock)
355 { 366 {
356 /* Failing that, see if LOGNAME or USER exist and differ from 367 /* Failing that, see if LOGNAME or USER exist and differ from
357 our euid. If so, look for a socket based on the UID 368 our euid. If so, look for a socket based on the UID
358 associated with the name. This is reminiscent of the logic 369 associated with the name. This is reminiscent of the logic
359 that init_editfns uses to set the global Vuser_full_name. */ 370 that init_editfns uses to set the global Vuser_full_name. */
360 371
361 char *user_name = (char *) getenv ("LOGNAME"); 372 char *user_name = (char *) getenv ("LOGNAME");
373
362 if (!user_name) 374 if (!user_name)
363 user_name = (char *) getenv ("USER"); 375 user_name = (char *) getenv ("USER");
364 376
365 if (user_name) 377 if (user_name)
366 { 378 {
367 struct passwd *pw = getpwnam (user_name); 379 struct passwd *pw = getpwnam (user_name);
380
368 if (pw && (pw->pw_uid != geteuid ())) 381 if (pw && (pw->pw_uid != geteuid ()))
369 { 382 {
370 /* We're running under su, apparently. */ 383 /* We're running under su, apparently. */
371 sprintf (server.sun_path, "/tmp/esrv%d-%s", 384 socket_name = alloca (100 + strlen (server_name));
372 (int) pw->pw_uid, system_name); 385 sprintf (socket_name, "/tmp/emacs%d/%s",
386 (int) pw->pw_uid, server_name);
387
388 if (strlen (socket_name) < sizeof (server.sun_path))
389 strcpy (server.sun_path, socket_name);
390 else
391 {
392 fprintf (stderr, "%s: socket-name %s too long",
393 argv[0], socket_name);
394 exit (1);
395 }
396
373 sock_status = socket_status (server.sun_path); 397 sock_status = socket_status (server.sun_path);
398 saved_errno = errno;
374 } 399 }
400 else
401 errno = saved_errno;
375 } 402 }
376 } 403 }
377 404
378 switch (sock_status) 405 switch (sock_status)
379 { 406 {
387 } 414 }
388 break; 415 break;
389 416
390 case 2: 417 case 2:
391 /* `stat' failed */ 418 /* `stat' failed */
392 if (errno == ENOENT) 419 if (saved_errno == ENOENT)
393 fprintf (stderr, 420 fprintf (stderr,
394 "%s: can't find socket; have you started the server?\n\ 421 "%s: can't find socket; have you started the server?\n\
395 To start the server in Emacs, type \"M-x server-start\".\n", 422 To start the server in Emacs, type \"M-x server-start\".\n",
396 argv[0]); 423 argv[0]);
397 else 424 else
398 fprintf (stderr, "%s: can't stat %s: %s\n", 425 fprintf (stderr, "%s: can't stat %s: %s\n",
399 argv[0], server.sun_path, strerror (errno)); 426 argv[0], server.sun_path, strerror (saved_errno));
400 fail (argc, argv); 427 fail (argc, argv);
401 break; 428 break;
402 } 429 }
403 } 430 }
404 431
453 480
454 if (eval) 481 if (eval)
455 fprintf (out, "-eval "); 482 fprintf (out, "-eval ");
456 483
457 if (display) 484 if (display)
458 fprintf (out, "-display %s ", quote_file_name (display)); 485 {
459 486 fprintf (out, "-display ");
460 for (i = optind; i < argc; i++) 487 quote_file_name (display, out);
461 { 488 fprintf (out, " ");
462 if (eval) 489 }
463 ; /* Don't prepend any cwd or anything like that. */ 490
464 else if (*argv[i] == '+') 491 if ((argc - optind > 0))
492 {
493 for (i = optind; i < argc; i++)
465 { 494 {
466 char *p = argv[i] + 1; 495 if (eval)
467 while (isdigit ((unsigned char) *p) || *p == ':') p++; 496 ; /* Don't prepend any cwd or anything like that. */
468 if (*p != 0) 497 else if (*argv[i] == '+')
469 fprintf (out, "%s/", quote_file_name (cwd)); 498 {
499 char *p = argv[i] + 1;
500 while (isdigit ((unsigned char) *p) || *p == ':') p++;
501 if (*p != 0)
502 {
503 quote_file_name (cwd, out);
504 fprintf (out, "/");
505 }
506 }
507 else if (*argv[i] != '/')
508 {
509 quote_file_name (cwd, out);
510 fprintf (out, "/");
511 }
512
513 quote_file_name (argv[i], out);
514 fprintf (out, " ");
470 } 515 }
471 else if (*argv[i] != '/') 516 }
472 fprintf (out, "%s/", quote_file_name (cwd)); 517 else
473 518 {
474 fprintf (out, "%s ", quote_file_name (argv[i])); 519 while ((str = fgets (string, BUFSIZ, stdin)))
475 } 520 {
521 quote_file_name (str, out);
522 }
523 fprintf (out, " ");
524 }
525
476 fprintf (out, "\n"); 526 fprintf (out, "\n");
477 fflush (out); 527 fflush (out);
478 528
479 /* Maybe wait for an answer. */ 529 /* Maybe wait for an answer. */
480 if (nowait) 530 if (nowait)
517 return sys_errlist[errnum]; 567 return sys_errlist[errnum];
518 return (char *) "Unknown error"; 568 return (char *) "Unknown error";
519 } 569 }
520 570
521 #endif /* ! HAVE_STRERROR */ 571 #endif /* ! HAVE_STRERROR */
572
573 /* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7
574 (do not change this comment) */