emacsclient.c 11.1 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Client process that communicates with GNU Emacs acting as server.
2
   Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003
3
   Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5 6 7 8

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
Richard M. Stallman's avatar
Richard M. Stallman committed
10 11 12 13 14 15 16 17 18
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
19 20
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
21 22 23


#define NO_SHORTNAMES
24 25

#ifdef HAVE_CONFIG_H
Pavel Janík's avatar
Pavel Janík committed
26
#include <config.h>
27 28
#endif

29
#undef signal
Richard M. Stallman's avatar
Richard M. Stallman committed
30

31
#include <ctype.h>
32 33
#include <stdio.h>
#include <getopt.h>
34 35 36
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
37

38 39 40 41 42 43
#ifdef VMS
# include "vms-pwd.h"
#else
# include <pwd.h>
#endif /* not VMS */

44 45 46 47 48 49 50 51 52 53 54 55 56
char *getenv (), *getwd ();
char *getcwd ();

/* This is defined with -D from the compilation command,
   which extracts it from ../lisp/version.el.  */

#ifndef VERSION
#define VERSION "unspecified"
#endif

/* Name used to invoke this program.  */
char *progname;

57
/* Nonzero means don't wait for a response from Emacs.  --no-wait.  */
58 59
int nowait = 0;

Stefan Monnier's avatar
Stefan Monnier committed
60 61 62 63 64 65 66 67 68 69
/* Nonzero means args are expressions to be evaluated.  --eval.  */
int eval = 0;

/* The display on which Emacs should work.  --display.  */
char *display = NULL;

/* If non-NULL, the name of an editor to fallback to if the server
   is not running.  --alternate-editor.   */
const char * alternate_editor = NULL;

70 71
void print_help_and_exit ();

72 73
struct option longopts[] =
{
74
  { "no-wait",	no_argument,	   NULL, 'n' },
Stefan Monnier's avatar
Stefan Monnier committed
75
  { "eval",	no_argument,	   NULL, 'e' },
76 77
  { "help",	no_argument,	   NULL, 'H' },
  { "version",	no_argument,	   NULL, 'V' },
Stefan Monnier's avatar
Stefan Monnier committed
78
  { "alternate-editor", required_argument, NULL, 'a' },
Stefan Monnier's avatar
Stefan Monnier committed
79 80
  { "display",	required_argument, NULL, 'd' },
  { 0, 0, 0, 0 }
81 82 83
};

/* Decode the options from argv and argc.
84
   The global variable `optind' will say how many arguments we used up.  */
85

86
void
87 88 89 90 91 92 93
decode_options (argc, argv)
     int argc;
     char **argv;
{
  while (1)
    {
      int opt = getopt_long (argc, argv,
Stefan Monnier's avatar
Stefan Monnier committed
94
			     "VHnea:d:", longopts, 0);
95 96 97 98

      if (opt == EOF)
	break;

99
      alternate_editor = getenv ("ALTERNATE_EDITOR");
100

101 102 103 104 105 106
      switch (opt)
	{
	case 0:
	  /* If getopt returns 0, then it has already processed a
	     long-named option.  We should do nothing.  */
	  break;
107

108 109 110
	case 'a':
	  alternate_editor = optarg;
	  break;
111

Stefan Monnier's avatar
Stefan Monnier committed
112 113 114 115
	case 'd':
	  display = optarg;
	  break;

116 117 118 119
	case 'n':
	  nowait = 1;
	  break;

Stefan Monnier's avatar
Stefan Monnier committed
120 121 122 123
	case 'e':
	  eval = 1;
	  break;

124
	case 'V':
125 126
	  printf ("emacsclient %s\n", VERSION);
	  exit (0);
127
	  break;
Richard M. Stallman's avatar
Richard M. Stallman committed
128

129 130
	case 'H':
	  print_help_and_exit ();
131 132 133 134 135 136
	  break;

	default:
	  fprintf (stderr, "Try `%s --help' for more information\n", progname);
	  exit (1);
	  break;
137 138 139 140
	}
    }
}

141
void
142 143
print_help_and_exit ()
{
144 145
  printf (
	  "Usage: %s [OPTIONS] FILE...\n\
Stefan Monnier's avatar
Stefan Monnier committed
146 147
Tell the Emacs server to visit the specified files.\n\
Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
148
\n\
Stefan Monnier's avatar
Stefan Monnier committed
149 150 151 152 153 154 155 156
The following OPTIONS are accepted:\n\
-V, --version           Just print a version info and return\n\
-H, --help              Print this usage information message\n\
-n, --no-wait           Don't wait for the server to return\n\
-e, --eval              Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY   Visit the file in the given display\n\
-a, --alternate-editor=EDITOR\n\
                        Editor to fallback to if the server is not running\n\
157
\n\
Stefan Monnier's avatar
Stefan Monnier committed
158
Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
159
  exit (0);
160
}
161

162
/* Return a copy of NAME, inserting a &
Stefan Monnier's avatar
Stefan Monnier committed
163
   before each &, each space, each newline, and any initial -.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
   Change spaces to underscores, too, so that the
   return value never contains a space.  */

char *
quote_file_name (name)
     char *name;
{
  char *copy = (char *) malloc (strlen (name) * 2 + 1);
  char *p, *q;

  p = name;
  q = copy;
  while (*p)
    {
      if (*p == ' ')
	{
180
	  *q++ = '&';
181 182 183
	  *q++ = '_';
	  p++;
	}
Stefan Monnier's avatar
Stefan Monnier committed
184 185 186 187 188 189
      else if (*p == '\n')
	{
	  *q++ = '&';
	  *q++ = 'n';
	  p++;
	}
190 191
      else
	{
192 193
	  if (*p == '&' || (*p == '-' && p == name))
	    *q++ = '&';
194 195 196
	  *q++ = *p++;
	}
    }
197
  *q++ = 0;
198 199 200

  return copy;
}
201 202 203

/* Like malloc but get fatal error if memory is exhausted.  */

204
long *
205 206 207
xmalloc (size)
     unsigned int size;
{
208
  long *result = (long *) malloc (size);
209 210 211 212 213 214 215
  if (result == NULL)
  {
    perror ("malloc");
    exit (1);
  }
  return result;
}
216 217 218 219 220

/*
  Try to run a different command, or --if no alternate editor is
  defined-- exit with an errorcode.
*/
221
void
222 223 224 225 226 227
fail (argc, argv)
     int argc;
     char **argv;
{
  if (alternate_editor)
    {
Stefan Monnier's avatar
Stefan Monnier committed
228
      int i = optind - 1;
229
      execvp (alternate_editor, argv + i);
Dave Love's avatar
Dave Love committed
230
      return;
231 232 233 234 235 236 237 238
    }
  else
    {
      exit (1);
    }
}


239

Stefan Monnier's avatar
Stefan Monnier committed
240
#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
Richard M. Stallman's avatar
Richard M. Stallman committed
241

242
int
Richard M. Stallman's avatar
Richard M. Stallman committed
243 244 245 246 247 248
main (argc, argv)
     int argc;
     char **argv;
{
  fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
	   argv[0]);
Stefan Monnier's avatar
Stefan Monnier committed
249
  fprintf (stderr, "on systems with Berkeley sockets.\n");
250 251

  fail (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
252 253
}

Stefan Monnier's avatar
Stefan Monnier committed
254
#else /* HAVE_SOCKETS */
Richard M. Stallman's avatar
Richard M. Stallman committed
255 256 257 258

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
Jim Blandy's avatar
Jim Blandy committed
259
#include <sys/stat.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
260 261
#include <errno.h>

262
extern char *strerror ();
Richard M. Stallman's avatar
Richard M. Stallman committed
263 264
extern int errno;

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
/* Three possibilities:
   2 - can't be `stat'ed		(sets errno)
   1 - isn't owned by us
   0 - success: none of the above */

static int
socket_status (socket_name)
     char *socket_name;
{
  struct stat statbfr;

  if (stat (socket_name, &statbfr) == -1)
    return 2;

  if (statbfr.st_uid != geteuid ())
    return 1;

  return 0;
}

285
int
Richard M. Stallman's avatar
Richard M. Stallman committed
286 287 288 289
main (argc, argv)
     int argc;
     char **argv;
{
290 291
  char *system_name;
  int system_name_length;
Stefan Monnier's avatar
Stefan Monnier committed
292
  int s, i, needlf = 0;
293
  FILE *out, *in;
Richard M. Stallman's avatar
Richard M. Stallman committed
294
  struct sockaddr_un server;
295
  char *cwd, *str;
Richard M. Stallman's avatar
Richard M. Stallman committed
296
  char string[BUFSIZ];
297 298

  progname = argv[0];
Richard M. Stallman's avatar
Richard M. Stallman committed
299

300
  /* Process options.  */
301
  decode_options (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
302

303
  if (argc - optind < 1)
304 305 306 307 308
    {
      fprintf (stderr, "%s: file name or argument required\n", progname);
      fprintf (stderr, "Try `%s --help' for more information\n", progname);
      exit (1);
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
309

310
  /*
Richard M. Stallman's avatar
Richard M. Stallman committed
311 312 313 314 315 316 317
   * Open up an AF_UNIX socket in this person's home directory
   */

  if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
      fprintf (stderr, "%s: ", argv[0]);
      perror ("socket");
318
      fail (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
319
    }
320

Richard M. Stallman's avatar
Richard M. Stallman committed
321
  server.sun_family = AF_UNIX;
322

Jim Blandy's avatar
Jim Blandy committed
323
  {
324
    char *dot;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    system_name_length = 32;

    while (1)
      {
	system_name = (char *) xmalloc (system_name_length + 1);

	/* system_name must be null-terminated string.  */
	system_name[system_name_length] = '\0';

 	if (gethostname (system_name, system_name_length) == 0)
	  break;

	free (system_name);
	system_name_length *= 2;
      }
340 341 342 343 344

    /* We always use the non-dotted host name, for simplicity.  */
    dot = index (system_name, '.');
    if (dot)
      *dot = '\0';
345 346 347
  }

  {
348
    int sock_status = 0;
Jim Blandy's avatar
Jim Blandy committed
349

350
    sprintf (server.sun_path, "/tmp/emacs%d-%s/server", (int) geteuid (), system_name);
Jim Blandy's avatar
Jim Blandy committed
351

352 353 354
    /* See if the socket exists, and if it's owned by us. */
    sock_status = socket_status (server.sun_path);
    if (sock_status)
Jim Blandy's avatar
Jim Blandy committed
355
      {
356 357 358 359
	/* Failing that, see if LOGNAME or USER exist and differ from
	   our euid.  If so, look for a socket based on the UID
	   associated with the name.  This is reminiscent of the logic
	   that init_editfns uses to set the global Vuser_full_name.  */
360

361 362 363
	char *user_name = (char *) getenv ("LOGNAME");
	if (!user_name)
	  user_name = (char *) getenv ("USER");
364

365 366 367 368 369 370 371
	if (user_name)
	  {
	    struct passwd *pw = getpwnam (user_name);
	    if (pw && (pw->pw_uid != geteuid ()))
	      {
		/* We're running under su, apparently. */
		sprintf (server.sun_path, "/tmp/esrv%d-%s",
Dave Love's avatar
Dave Love committed
372
			 (int) pw->pw_uid, system_name);
373 374 375
		sock_status = socket_status (server.sun_path);
	      }
	  }
Jim Blandy's avatar
Jim Blandy committed
376
      }
377

378 379 380 381 382 383 384 385 386 387 388
     switch (sock_status)
       {
       case 1:
	 /* There's a socket, but it isn't owned by us.  This is OK if
	    we are root. */
	 if (0 != geteuid ())
	   {
	     fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
	     fail (argc, argv);
	   }
	 break;
389

390 391 392 393
       case 2:
	 /* `stat' failed */
	 if (errno == ENOENT)
	   fprintf (stderr,
394 395
		    "%s: can't find socket; have you started the server?\n\
To start the server in Emacs, type \"M-x server-start\".\n",
396 397 398 399 400 401 402
		    argv[0]);
	 else
	   fprintf (stderr, "%s: can't stat %s: %s\n",
		    argv[0], server.sun_path, strerror (errno));
	 fail (argc, argv);
	 break;
       }
Jim Blandy's avatar
Jim Blandy committed
403
  }
Richard M. Stallman's avatar
Richard M. Stallman committed
404

405 406
  if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
      < 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
407 408 409
    {
      fprintf (stderr, "%s: ", argv[0]);
      perror ("connect");
410
      fail (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
411
    }
412 413

  /* We use the stream OUT to send our command to the server.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
414 415 416 417
  if ((out = fdopen (s, "r+")) == NULL)
    {
      fprintf (stderr, "%s: ", argv[0]);
      perror ("fdopen");
418
      fail (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
419 420
    }

421 422 423 424 425 426 427 428 429
  /* We use the stream IN to read the response.
     We used to use just one stream for both output and input
     on the socket, but reversing direction works nonportably:
     on some systems, the output appears as the first input;
     on other systems it does not.  */
  if ((in = fdopen (s, "r+")) == NULL)
    {
      fprintf (stderr, "%s: ", argv[0]);
      perror ("fdopen");
430
      fail (argc, argv);
431 432
    }

433
#ifdef HAVE_GETCWD
434
  cwd = getcwd (string, sizeof string);
435 436
#else
  cwd = getwd (string);
437
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
438 439 440
  if (cwd == 0)
    {
      /* getwd puts message in STRING if it fails.  */
441

442
#ifdef HAVE_GETCWD
443 444
      fprintf (stderr, "%s: %s (%s)\n", argv[0],
	       "Cannot get current working directory", strerror (errno));
445
#else
446
      fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
447
#endif
448
      fail (argc, argv);
Richard M. Stallman's avatar
Richard M. Stallman committed
449 450
    }

451 452
  if (nowait)
    fprintf (out, "-nowait ");
453

Stefan Monnier's avatar
Stefan Monnier committed
454 455 456 457 458 459
  if (eval)
    fprintf (out, "-eval ");

  if (display)
    fprintf (out, "-display %s ", quote_file_name (display));

460 461
  for (i = optind; i < argc; i++)
    {
Stefan Monnier's avatar
Stefan Monnier committed
462 463 464
      if (eval)
	; /* Don't prepend any cwd or anything like that.  */
      else if (*argv[i] == '+')
Richard M. Stallman's avatar
Richard M. Stallman committed
465 466
	{
	  char *p = argv[i] + 1;
467
	  while (isdigit ((unsigned char) *p) || *p == ':') p++;
Richard M. Stallman's avatar
Richard M. Stallman committed
468
	  if (*p != 0)
469
	    fprintf (out, "%s/", quote_file_name (cwd));
Richard M. Stallman's avatar
Richard M. Stallman committed
470 471
	}
      else if (*argv[i] != '/')
472
	fprintf (out, "%s/", quote_file_name (cwd));
473 474

      fprintf (out, "%s ", quote_file_name (argv[i]));
Richard M. Stallman's avatar
Richard M. Stallman committed
475 476 477 478
    }
  fprintf (out, "\n");
  fflush (out);

479 480 481 482
  /* Maybe wait for an answer.   */
  if (nowait)
    return 0;

Stefan Monnier's avatar
Stefan Monnier committed
483 484 485 486 487
  if (!eval)
    {
      printf ("Waiting for Emacs...");
      needlf = 2;
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
488 489
  fflush (stdout);

Stefan Monnier's avatar
Stefan Monnier committed
490
  /* Now, wait for an answer and print any messages.  */
491
  while ((str = fgets (string, BUFSIZ, in)))
Stefan Monnier's avatar
Stefan Monnier committed
492 493 494 495 496 497 498 499 500 501
    {
      if (needlf == 2)
	printf ("\n");
      printf ("%s", str);
      needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
    }

  if (needlf)
    printf ("\n");
  fflush (stdout);
502

503
  return 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
504 505
}

Stefan Monnier's avatar
Stefan Monnier committed
506
#endif /* HAVE_SOCKETS */
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521

#ifndef HAVE_STRERROR
char *
strerror (errnum)
     int errnum;
{
  extern char *sys_errlist[];
  extern int sys_nerr;

  if (errnum >= 0 && errnum < sys_nerr)
    return sys_errlist[errnum];
  return (char *) "Unknown error";
}

#endif /* ! HAVE_STRERROR */