Mercurial > emacs
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) */ |